import type { PropertyValues } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, query } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../common/dom/fire_event";
import { stringCompare } from "../common/string/compare";
import type { Blueprint, BlueprintDomain, Blueprints } from "../data/blueprint";
import { fetchBlueprints } from "../data/blueprint";
import type { HomeAssistant } from "../types";
import type { HaSelectSelectEvent } from "./ha-select";
import "./ha-select";

@customElement("ha-blueprint-picker")
class HaBluePrintPicker extends LitElement {
  public hass?: HomeAssistant;

  @property() public label?: string;

  @property() public value = "";

  @property() public domain: BlueprintDomain = "automation";

  @property({ attribute: false }) public blueprints?: Blueprints;

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

  @query("ha-select") private _select?: HTMLElement;

  public open() {
    if (this._select) {
      // @ts-expect-error
      this._select.menuOpen = true;
    }
  }

  private _processedBlueprints = memoizeOne((blueprints?: Blueprints) => {
    if (!blueprints) {
      return [];
    }
    const result = Object.entries(blueprints)
      .filter((entry): entry is [string, Blueprint] => !("error" in entry[1]))
      .map(([path, blueprint]) => ({
        ...blueprint.metadata,
        path,
      }));
    return result.sort((a, b) =>
      stringCompare(a.name, b.name, this.hass!.locale.language)
    );
  });

  protected render() {
    if (!this.hass) {
      return nothing;
    }
    return html`
      <ha-select
        .label=${
          this.label ||
          this.hass.localize("ui.components.blueprint-picker.select_blueprint")
        }
        .value=${this.value}
        .disabled=${this.disabled}
        @selected=${this._blueprintChanged}
        .options=${this._processedBlueprints(this.blueprints).map(
          (blueprint) => ({
            value: blueprint.path,
            label: blueprint.name,
          })
        )}
      >
      </ha-select>
    `;
  }

  protected firstUpdated(changedProps: PropertyValues<this>) {
    super.firstUpdated(changedProps);
    if (this.blueprints === undefined) {
      fetchBlueprints(this.hass!, this.domain).then((blueprints) => {
        this.blueprints = blueprints;
      });
    }
  }

  private _blueprintChanged(ev: HaSelectSelectEvent) {
    const newValue = ev.detail.value;

    if (newValue !== this.value) {
      this.value = newValue;
      setTimeout(() => {
        fireEvent(this, "value-changed", { value: newValue });
        fireEvent(this, "change");
      }, 0);
    }
  }

  static styles = css`
    :host {
      display: inline-block;
    }
    ha-select {
      width: 100%;
      min-width: 200px;
      display: block;
    }
  `;
}

declare global {
  interface HTMLElementTagNameMap {
    "ha-blueprint-picker": HaBluePrintPicker;
  }
}
