import {Component, Element, EventEmitter, h, Listen, Prop, State} from '@stencil/core';
import {AppIcon} from '../../../components/core/app-icon/app-icon';
import i18n from '../../../stores/i18n.store';
import {PrismLanguage} from '../../../types/editor/prism-language';
import {filterCodeLanguages} from '../../../utils/editor/prism.utils';

@Component({
  tag: 'app-code-languages',
  styleUrl: 'app-code-languages.scss'
})
export class AppCodeLanguages {
  @Element() el: HTMLElement;

  @Prop()
  selectedTarget: HTMLElement;

  @Prop()
  codeDidChange: EventEmitter<HTMLElement> | undefined;

  @Prop()
  currentLanguage: PrismLanguage | undefined;

  @State()
  private filteredLanguages: PrismLanguage[];

  @State()
  private filter: string;

  private input: HTMLIonSearchbarElement | undefined;

  async componentWillLoad() {
    await this.search();
  }

  componentDidLoad() {
    history.pushState({modal: true}, null);

    setTimeout(async () => await this.input?.setFocus(), 500);
  }

  @Listen('popstate', {target: 'window'})
  async handleHardwareBackButton(_e: PopStateEvent) {
    await this.closeModal();
  }

  async closeModal(selectedLanguage?: PrismLanguage) {
    await (this.el.closest('ion-modal') as HTMLIonModalElement).dismiss(selectedLanguage);
  }

  private search() {
    const filtered: PrismLanguage[] = filterCodeLanguages(this.filter);
    this.filteredLanguages = [...filtered];
  }

  private clear() {
    this.filter = undefined;

    this.search();
  }

  private handleInput($event: CustomEvent<KeyboardEvent>) {
    this.filter = ($event.target as InputTargetEvent).value;
  }

  private selectCodeLanguage(language: PrismLanguage): Promise<void> {
    return new Promise<void>(async (resolve) => {
      if (!this.selectedTarget) {
        resolve();
        return;
      }

      if (!language) {
        resolve();
        return;
      }

      const currentLanguage: string = this.selectedTarget.getAttribute('language');

      if (language.language === currentLanguage) {
        await this.closeModal(language);

        resolve();
        return;
      }

      this.selectedTarget.setAttribute('language', language.language);

      // Reload component with new language
      await (this.selectedTarget as any).load();

      this.codeDidChange?.emit(this.selectedTarget);

      await this.closeModal(language);

      resolve();
    });
  }

  render() {
    return [
      <ion-header>
        <ion-toolbar color="primary">
          <ion-buttons slot="start">
            <ion-button onClick={() => this.closeModal()} aria-label={i18n.state.core.close}>
              <AppIcon name="close" ariaHidden={true} ariaLabel=""></AppIcon>
            </ion-button>
          </ion-buttons>
          <ion-title class="ion-text-uppercase">{i18n.state.editor.languages}</ion-title>
        </ion-toolbar>
      </ion-header>,
      <ion-content class="ion-padding">
        <ion-list>
          <ion-radio-group value={this.currentLanguage ? this.currentLanguage.language : undefined}>
            {this.renderLanguages()}
          </ion-radio-group>
        </ion-list>
      </ion-content>,
      <ion-footer>
        <ion-toolbar>
          <ion-searchbar
            debounce={500}
            placeholder={i18n.state.editor.filter_languages}
            ref={(el) => (this.input = el as HTMLIonSearchbarElement)}
            value={this.filter}
            onIonClear={() => this.clear()}
            onIonInput={(e: CustomEvent<KeyboardEvent>) => this.handleInput(e)}
            onIonChange={() => {
              this.search();
            }}></ion-searchbar>
        </ion-toolbar>
      </ion-footer>
    ];
  }

  private renderLanguages() {
    if (this.filteredLanguages) {
      return this.filteredLanguages.map((language: PrismLanguage) => {
        return (
          <ion-item key={language.language} onClick={() => this.selectCodeLanguage(language)} class="ion-margin-end">
            <ion-label>{language.title}</ion-label>
            <ion-radio value={language.language} mode="ios" />
          </ion-item>
        );
      });
    } else {
      return undefined;
    }
  }
}
