import { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket";
import {
  css,
  CSSResultGroup,
  html,
  LitElement,
  PropertyValues,
  TemplateResult,
} from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../common/dom/fire_event";
import {
  AreaRegistryEntry,
  subscribeAreaRegistry,
} from "../data/area_registry";
import { ConfigEntry, getConfigEntries } from "../data/config_entries";
import {
  DeviceRegistryEntry,
  subscribeDeviceRegistry,
} from "../data/device_registry";
import { SceneEntity } from "../data/scene";
import { findRelated, ItemType, RelatedResult } from "../data/search";
import { SubscribeMixin } from "../mixins/subscribe-mixin";
import { HomeAssistant } from "../types";
import "./ha-switch";

@customElement("ha-related-items")
export class HaRelatedItems extends SubscribeMixin(LitElement) {
  @property({ attribute: false }) public hass!: HomeAssistant;

  @property() public itemType!: ItemType;

  @property() public itemId!: string;

  @state() private _entries?: ConfigEntry[];

  @state() private _devices?: DeviceRegistryEntry[];

  @state() private _areas?: AreaRegistryEntry[];

  @state() private _related?: RelatedResult;

  public hassSubscribe(): UnsubscribeFunc[] {
    return [
      subscribeDeviceRegistry(this.hass.connection!, (devices) => {
        this._devices = devices;
      }),
      subscribeAreaRegistry(this.hass.connection!, (areas) => {
        this._areas = areas;
      }),
    ];
  }

  protected firstUpdated(changedProps: PropertyValues) {
    super.firstUpdated(changedProps);
    getConfigEntries(this.hass).then((configEntries) => {
      this._entries = configEntries;
    });
    this.hass.loadBackendTranslation("title");
  }

  protected updated(changedProps: PropertyValues) {
    super.updated(changedProps);
    if (
      (changedProps.has("itemId") || changedProps.has("itemType")) &&
      this.itemId &&
      this.itemType
    ) {
      this._findRelated();
    }
  }

  protected render(): TemplateResult {
    if (!this._related) {
      return html``;
    }
    if (Object.keys(this._related).length === 0) {
      return html`
        ${this.hass.localize("ui.components.related-items.no_related_found")}
      `;
    }
    return html`
      ${this._related.config_entry && this._entries
        ? this._related.config_entry.map((relatedConfigEntryId) => {
            const entry: ConfigEntry | undefined = this._entries!.find(
              (configEntry) => configEntry.entry_id === relatedConfigEntryId
            );
            if (!entry) {
              return "";
            }
            return html`
              <h3>
                ${this.hass.localize(
                  "ui.components.related-items.integration"
                )}:
              </h3>
              <a
                href=${`/config/integrations#config_entry=${relatedConfigEntryId}`}
                @click=${this._navigateAwayClose}
              >
                ${this.hass.localize(`component.${entry.domain}.title`)}:
                ${entry.title}
              </a>
            `;
          })
        : ""}
      ${this._related.device && this._devices
        ? this._related.device.map((relatedDeviceId) => {
            const device: DeviceRegistryEntry | undefined = this._devices!.find(
              (dev) => dev.id === relatedDeviceId
            );
            if (!device) {
              return "";
            }
            return html`
              <h3>
                ${this.hass.localize("ui.components.related-items.device")}:
              </h3>
              <a
                href="/config/devices/device/${relatedDeviceId}"
                @click=${this._navigateAwayClose}
              >
                ${device.name_by_user || device.name}
              </a>
            `;
          })
        : ""}
      ${this._related.area && this._areas
        ? this._related.area.map((relatedAreaId) => {
            const area: AreaRegistryEntry | undefined = this._areas!.find(
              (ar) => ar.area_id === relatedAreaId
            );
            if (!area) {
              return "";
            }
            return html`
              <h3>
                ${this.hass.localize("ui.components.related-items.area")}:
              </h3>
              <a
                href="/config/areas/area/${relatedAreaId}"
                @click=${this._navigateAwayClose}
              >
                ${area.name}
              </a>
            `;
          })
        : ""}
      ${this._related.entity
        ? html`
            <h3>
              ${this.hass.localize("ui.components.related-items.entity")}:
            </h3>
            <ul>
              ${this._related.entity.map((entityId) => {
                const entity: HassEntity | undefined =
                  this.hass.states[entityId];
                if (!entity) {
                  return "";
                }
                return html`
                  <li>
                    <button
                      @click=${this._openMoreInfo}
                      .entityId=${entityId}
                      class="link"
                    >
                      ${entity.attributes.friendly_name || entityId}
                    </button>
                  </li>
                `;
              })}
            </ul>
          `
        : ""}
      ${this._related.group
        ? html`
            <h3>${this.hass.localize("ui.components.related-items.group")}:</h3>
            <ul>
              ${this._related.group.map((groupId) => {
                const group: HassEntity | undefined = this.hass.states[groupId];
                if (!group) {
                  return "";
                }
                return html`
                  <li>
                    <button
                      class="link"
                      @click=${this._openMoreInfo}
                      .entityId=${groupId}
                    >
                      ${group.attributes.friendly_name || group.entity_id}
                    </button>
                  </li>
                `;
              })}
            </ul>
          `
        : ""}
      ${this._related.scene
        ? html`
            <h3>${this.hass.localize("ui.components.related-items.scene")}:</h3>
            <ul>
              ${this._related.scene.map((sceneId) => {
                const scene: SceneEntity | undefined =
                  this.hass.states[sceneId];
                if (!scene) {
                  return "";
                }
                return html`
                  <li>
                    <button
                      class="link"
                      @click=${this._openMoreInfo}
                      .entityId=${sceneId}
                    >
                      ${scene.attributes.friendly_name || scene.entity_id}
                    </button>
                  </li>
                `;
              })}
            </ul>
          `
        : ""}
      ${this._related.automation
        ? html`
            <h3>
              ${this.hass.localize("ui.components.related-items.automation")}:
            </h3>
            <ul>
              ${this._related.automation.map((automationId) => {
                const automation: HassEntity | undefined =
                  this.hass.states[automationId];
                if (!automation) {
                  return "";
                }
                return html`
                  <li>
                    <button
                      class="link"
                      @click=${this._openMoreInfo}
                      .entityId=${automationId}
                    >
                      ${automation.attributes.friendly_name ||
                      automation.entity_id}
                    </button>
                  </li>
                `;
              })}
            </ul>
          `
        : ""}
      ${this._related.script
        ? html`
            <h3>
              ${this.hass.localize("ui.components.related-items.script")}:
            </h3>
            <ul>
              ${this._related.script.map((scriptId) => {
                const script: HassEntity | undefined =
                  this.hass.states[scriptId];
                if (!script) {
                  return "";
                }
                return html`
                  <li>
                    <button
                      class="link"
                      @click=${this._openMoreInfo}
                      .entityId=${scriptId}
                    >
                      ${script.attributes.friendly_name || script.entity_id}
                    </button>
                  </li>
                `;
              })}
            </ul>
          `
        : ""}
    `;
  }

  private async _navigateAwayClose() {
    // allow new page to open before closing dialog
    await new Promise((resolve) => setTimeout(resolve, 0));
    fireEvent(this, "close-dialog");
  }

  private async _findRelated() {
    this._related = await findRelated(this.hass, this.itemType, this.itemId);
    await this.updateComplete;
    fireEvent(this, "iron-resize");
  }

  private _openMoreInfo(ev: CustomEvent) {
    const entityId = (ev.target as any).entityId;
    fireEvent(this, "hass-more-info", { entityId });
  }

  static get styles(): CSSResultGroup {
    return css`
      a {
        color: var(--primary-color);
      }
      button.link {
        color: var(--primary-color);
        text-align: left;
        cursor: pointer;
        background: none;
        border-width: initial;
        border-style: none;
        border-color: initial;
        border-image: initial;
        padding: 0px;
        font: inherit;
        text-decoration: underline;
      }
      h3 {
        font-family: var(--paper-font-title_-_font-family);
        -webkit-font-smoothing: var(
          --paper-font-title_-_-webkit-font-smoothing
        );
        font-size: var(--paper-font-title_-_font-size);
        font-weight: var(--paper-font-headline-_font-weight);
        letter-spacing: var(--paper-font-title_-_letter-spacing);
        line-height: var(--paper-font-title_-_line-height);
        opacity: var(--dark-primary-opacity);
      }
    `;
  }
}

declare global {
  interface HTMLElementTagNameMap {
    "ha-related-items": HaRelatedItems;
  }
}
