import { mdiDownload, mdiTrashCan } from "@mdi/js";
import { dump } from "js-yaml";
import type { CSSResultGroup } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { storage } from "../../../../common/decorators/storage";
import { formatLanguageCode } from "../../../../common/language/format_language";
import "../../../../components/ha-alert";
import "../../../../components/ha-button";
import "../../../../components/ha-card";
import "../../../../components/ha-code-editor";
import "../../../../components/ha-language-picker";
import "../../../../components/ha-textarea";
import type { HaTextArea } from "../../../../components/ha-textarea";
import type { AssistDebugResult } from "../../../../data/conversation";
import { debugAgent, listAgents } from "../../../../data/conversation";
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
import { haStyle } from "../../../../resources/styles";
import type { HomeAssistant } from "../../../../types";
import { fileDownload } from "../../../../util/file_download";

interface SentenceParsingResult {
  sentence: string;
  language: string;
  result: AssistDebugResult | null;
}

@customElement("tools-assist")
class HaPanelDevAssist extends SubscribeMixin(LitElement) {
  @property({ attribute: false }) public hass!: HomeAssistant;

  @property({ type: Boolean }) public narrow = false;

  @state() supportedLanguages?: string[];

  @state()
  @storage({
    key: "assist_debug_language",
    state: true,
    subscribe: false,
    storage: "localStorage",
  })
  _language?: string;

  @state() _results: SentenceParsingResult[] = [];

  @query("#sentences-input") _sentencesInput!: HaTextArea;

  @state() _validInput = false;

  private _languageChanged(ev) {
    this._language = ev.detail.value;
  }

  private _handleKeyDown(e: KeyboardEvent) {
    if (e.code !== "Enter" || e.shiftKey) {
      return;
    }
    e.preventDefault();
    this._parse();
  }

  private _textAreaInput(ev) {
    const value = ev.target.value;
    const valid = Boolean(value);
    if (valid !== this._validInput) {
      this._validInput = valid;
    }
  }

  private async _parse() {
    const sentences = (this._sentencesInput.value || "")
      .split("\n")
      .filter((a) => a !== "");
    const { results } = await debugAgent(this.hass, sentences, this._language!);

    this._sentencesInput.value = "";

    const newResults: SentenceParsingResult[] = [];
    sentences.forEach((sentence, index) => {
      const result = results[index];

      newResults.push({
        sentence,
        language: this._language!,
        result,
      });
    });
    this._results = [...newResults, ...this._results];
  }

  private async _fetchLanguages() {
    const { agents } = await listAgents(this.hass);
    const assistAgent = agents.find(
      (agent) => agent.id === "conversation.home_assistant"
    );
    this.supportedLanguages =
      assistAgent?.supported_languages === "*"
        ? undefined
        : assistAgent?.supported_languages;

    if (
      !this._language &&
      this.supportedLanguages?.includes(this.hass.locale.language)
    ) {
      this._language = this.hass.locale.language;
    } else if (!this._language) {
      this._language = "en";
    }
  }

  protected firstUpdated(): void {
    this._fetchLanguages();
  }

  protected render() {
    return html`
      <div class="content">
        <ha-card
          .header=${this.hass.localize(
            "ui.panel.config.tools.tabs.assist.title"
          )}
          class="form"
        >
          <div class="card-content">
            <p class="description">
              ${this.hass.localize(
                "ui.panel.config.tools.tabs.assist.description"
              )}
            </p>
            ${
              this.supportedLanguages
                ? html`
                    <ha-language-picker
                      .languages=${this.supportedLanguages}
                      .hass=${this.hass}
                      .value=${this._language}
                      @value-changed=${this._languageChanged}
                    ></ha-language-picker>
                  `
                : nothing
            }
            <ha-textarea
              resize="auto"
              .label=${this.hass.localize(
                "ui.panel.config.tools.tabs.assist.sentences"
              )}
              id="sentences-input"
              @input=${this._textAreaInput}
              @keydown=${this._handleKeyDown}
            ></ha-textarea>
          </div>
          <div class="card-actions">
            <ha-button
              appearance="filled"
              @click=${this._parse}
              .disabled=${!this._language || !this._validInput}
            >
              ${this.hass.localize(
                "ui.panel.config.tools.tabs.assist.parse_sentences"
              )}
            </ha-button>
          </div>
        </ha-card>

        ${
          this._results.length
            ? html`
                <div class="result-toolbar">
                  <ha-button
                    appearance="filled"
                    @click=${this._clear}
                    variant="danger"
                  >
                    <ha-svg-icon
                      slot="start"
                      .path=${mdiTrashCan}
                    ></ha-svg-icon>
                    ${this.hass.localize("ui.common.clear")}
                  </ha-button>
                  <ha-button appearance="filled" @click=${this._download}>
                    <ha-svg-icon
                      slot="start"
                      .path=${mdiDownload}
                    ></ha-svg-icon>
                    ${this.hass.localize(
                      "ui.panel.config.tools.tabs.assist.download_results"
                    )}
                  </ha-button>
                </div>
              `
            : ""
        }
        ${this._results.map((r) => {
          const { sentence, result, language } = r;
          const matched = result != null;

          return html`
            <ha-card class="result">
              <div class="card-content">
                <div class="sentence">
                  <p>${sentence}</p>
                  <p>${matched ? "✅" : "❌"}</p>
                </div>
                <div class="info">
                  ${this.hass.localize(
                    "ui.panel.config.tools.tabs.assist.language"
                  )}:
                  ${formatLanguageCode(language, this.hass.locale)}
                  (${language})
                </div>
                ${
                  result
                    ? html`
                        <ha-code-editor
                          mode="yaml"
                          .value=${dump(result).trimRight()}
                          read-only
                          dir="ltr"
                        ></ha-code-editor>
                      `
                    : html`<ha-alert alert-type="error">
                        ${this.hass.localize(
                          "ui.panel.config.tools.tabs.assist.no_match"
                        )}
                      </ha-alert>`
                }
              </div>
            </ha-card>
          `;
        })}
      </div>
    `;
  }

  private _download() {
    fileDownload(
      `data:text/plain;charset=utf-8,${encodeURIComponent(
        JSON.stringify({ results: this._results }, null, 2)
      )}`,
      `intent_results.json`
    );
  }

  private _clear() {
    this._results = [];
  }

  static get styles(): CSSResultGroup {
    return [
      haStyle,
      css`
        .content {
          padding: var(--ha-space-7) var(--ha-space-5) var(--ha-space-4);
          max-width: 1040px;
          margin: 0 auto;
        }
        .card-content {
          display: flex;
          flex-direction: column;
          gap: var(--ha-space-4);
        }
        .description {
          margin: 0;
        }
        ha-textarea {
          width: 100%;
        }
        .card-actions {
          text-align: right;
        }
        .form {
          margin-bottom: var(--ha-space-4);
        }
        .result-toolbar {
          text-align: center;
          margin-bottom: var(--ha-space-4);
        }
        .result {
          margin-bottom: var(--ha-space-4);
        }
        .sentence {
          font-weight: var(--ha-font-weight-medium);
          margin-bottom: var(--ha-space-2);
          display: flex;
          flex-direction: row;
          justify-content: space-between;
        }
        .sentence p {
          margin: 0;
        }
        .info p {
          margin: 0;
        }
        ha-code-editor,
        ha-alert {
          display: block;
          margin-top: var(--ha-space-4);
        }
      `,
    ];
  }
}

declare global {
  interface HTMLElementTagNameMap {
    "tools-assist": HaPanelDevAssist;
  }
}
