import "@home-assistant/webawesome/dist/components/tag/tag";
import { consume } from "@lit/context";
import {
  mdiAlertOutline,
  mdiDevices,
  mdiHome,
  mdiLabel,
  mdiTextureBox,
  mdiUnfoldMoreVertical,
} from "@mdi/js";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import memoizeOne from "memoize-one";
import { computeCssColor } from "../../common/color/compute-color";
import { hex2rgb } from "../../common/color/convert-color";
import { fireEvent } from "../../common/dom/fire_event";
import { computeDeviceNameDisplay } from "../../common/entity/compute_device_name";
import { computeDomain } from "../../common/entity/compute_domain";
import { computeStateName } from "../../common/entity/compute_state_name";
import { slugify } from "../../common/string/slugify";
import { getConfigEntry } from "../../data/config_entries";
import { labelsContext } from "../../data/context";
import type { DeviceCompositeSplits } from "../../data/device/device_registry";
import { domainToName } from "../../data/integration";
import type { LabelRegistryEntry } from "../../data/label/label_registry";
import type { TargetType } from "../../data/target";
import type { HomeAssistant } from "../../types";
import { brandsUrl } from "../../util/brands-url";
import "../ha-domain-icon";
import { floorDefaultIconPath } from "../ha-floor-icon";
import "../ha-icon";
import "../ha-icon-button";
import "../ha-state-icon";
import "../ha-tooltip";

@customElement("ha-target-picker-value-chip")
export class HaTargetPickerValueChip extends LitElement {
  @property({ attribute: false }) public hass!: HomeAssistant;

  @property() public type!: TargetType;

  @property({ attribute: "item-id" }) public itemId!: string;

  @property({ attribute: false })
  public compositeSplits?: DeviceCompositeSplits;

  @state() private _domainName?: string;

  @state() private _iconImg?: string;

  @state()
  @consume({ context: labelsContext, subscribe: true })
  _labelRegistry!: LabelRegistryEntry[];

  protected render() {
    const { name, iconPath, fallbackIconPath, stateObject, color } =
      this._itemData(this.type, this.itemId);

    const split =
      this.type === "device" && !this.hass.devices?.[this.itemId]
        ? this.compositeSplits?.[this.itemId]
        : undefined;
    // Show the replaced reference using the primary replacement device's name,
    // falling back to the first still-existing split device if the primary
    // device itself was deleted. If no replacement device exists at all, fall
    // back to the normal "not found" display.
    const replacementDevice = split
      ? (split.primary_id && this.hass.devices?.[split.primary_id]) ||
        split.split_ids
          .map((id) => this.hass.devices?.[id])
          .find((device) => device)
      : undefined;
    const replaced = !!replacementDevice;
    const replacedName = replacementDevice
      ? computeDeviceNameDisplay(
          replacementDevice,
          this.hass.localize,
          this.hass.states
        )
      : undefined;

    return html`
      <wa-tag
        pill
        with-remove
        class=${classMap({ [this.type]: true, replaced })}
        style=${color ? `--color: rgb(${color});` : ""}
        @wa-remove=${this._removeItem}
      >
        <div class="icon">
          ${
            replaced
              ? html`<ha-svg-icon .path=${mdiAlertOutline}></ha-svg-icon>`
              : iconPath
                ? html`<ha-icon .icon=${iconPath}></ha-icon>`
                : this._iconImg
                  ? html`<img
                      alt=${this._domainName || ""}
                      width="24"
                      crossorigin="anonymous"
                      referrerpolicy="no-referrer"
                      src=${this._iconImg}
                    />`
                  : fallbackIconPath
                    ? html`<ha-svg-icon
                        .path=${fallbackIconPath}
                      ></ha-svg-icon>`
                    : stateObject
                      ? html`<ha-state-icon
                          .stateObj=${stateObject}
                        ></ha-state-icon>`
                      : nothing
          }
        </div>
        <span class="name">
          ${
            replaced
              ? replacedName ||
                this.hass.localize(
                  "ui.components.target-picker.replaced_device"
                )
              : name
          }
        </span>
        ${
          this.type === "entity" || replaced
            ? nothing
            : html`<ha-tooltip .for="expand-${slugify(this.itemId)}"
                  >${this.hass.localize(
                    `ui.components.target-picker.expand_${this.type}_id`
                  )}
                </ha-tooltip>
                <ha-icon-button
                  class="expand-btn mdc-chip__icon mdc-chip__icon--trailing"
                  .label=${this.hass.localize(
                    "ui.components.target-picker.expand"
                  )}
                  .path=${mdiUnfoldMoreVertical}
                  hide-title
                  .id="expand-${slugify(this.itemId)}"
                  .type=${this.type}
                  @click=${this._handleExpand}
                ></ha-icon-button>`
        }
      </wa-tag>
    `;
  }

  private _itemData = memoizeOne((type: TargetType, itemId: string) => {
    if (type === "floor") {
      const floor = this.hass.floors?.[itemId];
      return {
        name: floor?.name || itemId,
        iconPath: floor?.icon,
        fallbackIconPath: floor ? floorDefaultIconPath(floor) : mdiHome,
      };
    }
    if (type === "area") {
      const area = this.hass.areas?.[itemId];
      return {
        name: area?.name || itemId,
        iconPath: area?.icon,
        fallbackIconPath: mdiTextureBox,
      };
    }
    if (type === "device") {
      const device = this.hass.devices?.[itemId];

      if (device?.primary_config_entry) {
        this._getDeviceDomain(device.primary_config_entry);
      }

      return {
        name: device
          ? computeDeviceNameDisplay(
              device,
              this.hass.localize,
              this.hass.states
            )
          : itemId,
        fallbackIconPath: mdiDevices,
      };
    }
    if (type === "entity") {
      this._setDomainName(computeDomain(itemId));

      const stateObj = this.hass.states[itemId];
      return {
        name: computeStateName(stateObj) || itemId,
        stateObject: stateObj,
      };
    }

    // type label
    const label = this._labelRegistry.find((lab) => lab.label_id === itemId);
    let color = label?.color ? computeCssColor(label.color) : undefined;
    if (color?.startsWith("var(")) {
      const computedStyles = getComputedStyle(this);
      color = computedStyles.getPropertyValue(
        color.substring(4, color.length - 1)
      );
    }
    if (color?.startsWith("#")) {
      color = hex2rgb(color).join(",");
    }
    return {
      name: label?.name || itemId,
      iconPath: label?.icon,
      fallbackIconPath: mdiLabel,
      color,
    };
  });

  private _setDomainName(domain: string) {
    this._domainName = domainToName(this.hass.localize, domain);
  }

  private async _getDeviceDomain(configEntryId: string) {
    try {
      const data = await getConfigEntry(this.hass, configEntryId);
      const domain = data.config_entry.domain;
      this._iconImg = brandsUrl(
        {
          domain: domain,
          type: "icon",
          darkOptimized: this.hass.themes?.darkMode,
        },
        this.hass.auth.data.hassUrl
      );

      this._setDomainName(domain);
    } catch {
      // failed to load config entry -> ignore
    }
  }

  private _removeItem(ev: MouseEvent) {
    ev.stopPropagation();
    fireEvent(this, "remove-target-item", {
      type: this.type,
      id: this.itemId,
    });
  }

  private _handleExpand(ev: MouseEvent) {
    ev.stopPropagation();
    fireEvent(this, "expand-target-item", {
      type: this.type,
      id: this.itemId,
    });
  }

  static styles = css`
    :host {
      display: inline-block;
      max-width: 100%;
    }
    wa-tag {
      background-color: var(--card-background-color);
      border-width: var(--ha-border-width-md);
      padding-inline-start: 0;
      overflow: hidden;
      max-width: 100%;
      color: var(--primary-text-color);
    }

    wa-tag.entity {
      border-color: var(--ha-color-green-80);
      --background-color: var(--ha-color-green-80);
    }
    wa-tag.device {
      border-color: var(--ha-color-primary-80);
      --background-color: var(--ha-color-primary-80);
    }
    wa-tag.area {
      border-color: var(--ha-color-orange-80);
      --background-color: var(--ha-color-orange-80);
    }
    wa-tag.label {
      border-color: var(--color);
      --background-color: var(--color);
      --icon-primary-color: var(--primary-text-color);
    }
    wa-tag.replaced {
      border-color: var(--ha-color-border-warning-normal, var(--warning-color));
      --background-color: var(--warning-color);
      color: var(--ha-color-on-warning-normal, var(--warning-color));
    }

    .name {
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }

    .icon {
      background-color: var(--background-color);
      border-radius: var(--ha-border-radius-circle);
      padding: var(--ha-space-2) var(--ha-space-1);
      display: flex;
    }
    .expand-btn {
      --ha-icon-button-size: 16px;
      --mdc-icon-size: 14px;
    }
  `;
}

declare global {
  interface HTMLElementTagNameMap {
    "ha-target-picker-value-chip": HaTargetPickerValueChip;
  }
}
