import { mdiPlayCircleOutline } from "@mdi/js";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { storage } from "../../common/decorators/storage";
import { fireEvent } from "../../common/dom/fire_event";
import "../../components/buttons/ha-progress-button";
import "../../components/ha-dialog-footer";
import "../../components/ha-textarea";
import "../../components/ha-dialog";
import type { HaTextArea } from "../../components/ha-textarea";
import { convertTextToSpeech } from "../../data/tts";
import { haStyleDialog } from "../../resources/styles";
import type { HomeAssistant } from "../../types";
import { showAlertDialog } from "../generic/show-dialog-box";
import type { TTSTryDialogParams } from "./show-dialog-tts-try";

@customElement("dialog-tts-try")
export class TTSTryDialog extends LitElement {
  @property({ attribute: false }) public hass!: HomeAssistant;

  @state() private _loadingExample = false;

  @state() private _open = false;

  @state() private _params?: TTSTryDialogParams;

  @state() private _valid = false;

  @query("#message") private _messageInput?: HaTextArea;

  @storage({
    key: "ttsTryMessages",
    state: false,
    subscribe: false,
  })
  private _messages?: Record<string, string>;

  public showDialog(params: TTSTryDialogParams) {
    this._params = params;
    this._valid = Boolean(this._defaultMessage);
    this._open = true;
  }

  public closeDialog() {
    this._open = false;
  }

  private _dialogClosed() {
    this._params = undefined;
    fireEvent(this, "dialog-closed", { dialog: this.localName });
  }

  private get _defaultMessage() {
    const language = this._params!.language?.substring(0, 2);
    const userLanguage = this.hass.locale.language.substring(0, 2);
    // Load previous message in the right language
    if (language && this._messages?.[language]) {
      return this._messages[language];
    }
    // Only display example message if it's interface language
    if (language === userLanguage) {
      return this.hass.localize("ui.dialogs.tts-try.message_example");
    }
    return "";
  }

  protected render() {
    if (!this._params) {
      return nothing;
    }
    return html`
      <ha-dialog
        .open=${this._open}
        header-title=${this.hass.localize("ui.dialogs.tts-try.header")}
        @closed=${this._dialogClosed}
      >
        <ha-textarea
          resize="auto"
          id="message"
          .label=${this.hass.localize("ui.dialogs.tts-try.message")}
          .placeholder=${this.hass.localize(
            "ui.dialogs.tts-try.message_placeholder"
          )}
          .value=${this._defaultMessage}
          @input=${this._inputChanged}
          ?autofocus=${!this._defaultMessage}
        >
        </ha-textarea>

        <ha-dialog-footer slot="footer">
          <ha-progress-button
            slot="primaryAction"
            .progress=${this._loadingExample}
            ?autofocus=${Boolean(this._defaultMessage)}
            @click=${this._playExample}
            .disabled=${!this._valid}
            .iconPath=${mdiPlayCircleOutline}
          >
            ${this.hass.localize("ui.dialogs.tts-try.play")}
          </ha-progress-button>
        </ha-dialog-footer>
      </ha-dialog>
    `;
  }

  private async _inputChanged() {
    this._valid = Boolean(this._messageInput?.value);
  }

  private async _playExample() {
    const message = this._messageInput?.value;
    if (!message) {
      return;
    }

    const platform = this._params!.engine;
    const language = this._params!.language;
    const voice = this._params!.voice;

    if (language) {
      this._messages = {
        ...this._messages,
        [language.substring(0, 2)]: message,
      };
    }

    this._loadingExample = true;

    const audio = new Audio();
    audio.play();

    let url;
    try {
      const result = await convertTextToSpeech(this.hass, {
        platform,
        message,
        language,
        options: { voice },
      });
      url = result.path;
    } catch (err: any) {
      this._loadingExample = false;
      showAlertDialog(this, {
        text: `Unable to load example. ${err.error || err.body || err}`,
        warning: true,
      });
      return;
    }
    audio.src = url;
    audio.addEventListener("canplaythrough", () => audio.play());
    audio.addEventListener("playing", () => {
      this._loadingExample = false;
    });
    audio.addEventListener("error", () => {
      showAlertDialog(this, { title: "Error playing audio." });
      this._loadingExample = false;
    });
  }

  static styles = [
    haStyleDialog,
    css`
      ha-textarea,
      ha-select {
        width: 100%;
      }
      ha-select {
        margin-top: 8px;
      }
      .loading {
        height: 36px;
      }
    `,
  ];
}

declare global {
  interface HTMLElementTagNameMap {
    "dialog-tts-try": TTSTryDialog;
  }
}
