import type { HassEntity } from "home-assistant-js-websocket";
import type { CSSResultGroup, PropertyValues } from "lit";
import { css, html, LitElement } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { consume } from "@lit/context";
import { fireEvent } from "../../../common/dom/fire_event";
import { computeDeviceName } from "../../../common/entity/compute_device_name";
import { computeEntityEntryName } from "../../../common/entity/compute_entity_name";
import { getEntityEntryContext } from "../../../common/entity/context/get_entity_context";
import "../../../components/ha-alert";
import "../../../components/ha-button";
import type { ConfigEntry } from "../../../data/config_entries";
import {
  deleteConfigEntry,
  getConfigEntry,
} from "../../../data/config_entries";
import {
  dirtyStateContext,
  type DirtyStateContext,
} from "../../../data/context/dirty-state";
import { updateDeviceRegistryEntry } from "../../../data/device/device_registry";
import type { ExtEntityRegistryEntry } from "../../../data/entity/entity_registry";
import {
  removeEntityRegistryEntry,
  updateEntityRegistryEntry,
} from "../../../data/entity/entity_registry";
import { fetchIntegrationManifest } from "../../../data/integration";
import {
  showAlertDialog,
  showConfirmationDialog,
} from "../../../dialogs/generic/show-dialog-box";
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
import { haStyle } from "../../../resources/styles";
import type { HomeAssistant } from "../../../types";
import { showDeviceRegistryDetailDialog } from "../devices/device-registry-detail/show-dialog-device-registry-detail";
import "./entity-registry-settings-editor";
import type { EntityRegistrySettingsEditor } from "./entity-registry-settings-editor";
import { getDeleteConfirmationText } from "./get-delete-confirmation-text";

@customElement("entity-registry-settings")
export class EntityRegistrySettings extends SubscribeMixin(LitElement) {
  @property({ attribute: false }) public hass!: HomeAssistant;

  @property({ type: Object }) public entry!: ExtEntityRegistryEntry;

  @consume({ context: dirtyStateContext, subscribe: true })
  @state()
  private _dirtyState?: DirtyStateContext;

  @state() private _helperConfigEntry?: ConfigEntry;

  @state() private _error?: string;

  @state() private _submitting?: boolean;

  @query("entity-registry-settings-editor")
  private _registryEditor?: EntityRegistrySettingsEditor;

  protected willUpdate(changedProps: PropertyValues<this>): void {
    super.willUpdate(changedProps);
    if (changedProps.has("entry")) {
      this._fetchHelperConfigEntry();
    }
  }

  private async _fetchHelperConfigEntry() {
    this._helperConfigEntry = undefined;
    if (!this.entry?.config_entry_id) {
      return;
    }
    try {
      const configEntry = (
        await getConfigEntry(this.hass, this.entry.config_entry_id)
      ).config_entry;
      const manifest = await fetchIntegrationManifest(
        this.hass,
        configEntry.domain
      );
      if (manifest.integration_type === "helper") {
        this._helperConfigEntry = configEntry;
      }
      // eslint-disable-next-line no-empty
    } catch (_err) {}
  }

  protected render() {
    const stateObj: HassEntity | undefined =
      this.hass.states[this.entry.entity_id];

    const device = this.entry.device_id
      ? this.hass.devices[this.entry.device_id]
      : undefined;

    return html`
      ${
        !stateObj
          ? html`
              <ha-alert alert-type="warning">
                ${
                  device?.disabled_by
                    ? html`${this.hass!.localize(
                          "ui.dialogs.entity_registry.editor.device_disabled"
                        )}<ha-button
                          size="s"
                          variant="warning"
                          @click=${this._openDeviceSettings}
                          slot="action"
                        >
                          ${this.hass!.localize(
                            "ui.dialogs.entity_registry.editor.open_device_settings"
                          )}
                        </ha-button>`
                    : this.entry.disabled_by
                      ? html`${this.hass!.localize(
                          "ui.dialogs.entity_registry.editor.entity_disabled"
                        )}${
                          ["user", "integration"].includes(
                            this.entry.disabled_by!
                          )
                            ? html`<ha-button
                                size="s"
                                variant="warning"
                                slot="action"
                                @click=${this._enableEntry}
                              >
                                ${this.hass!.localize(
                                  "ui.dialogs.entity_registry.editor.enable_entity"
                                )}</ha-button
                              >`
                            : ""
                        }`
                      : this.hass!.localize(
                          "ui.dialogs.entity_registry.editor.unavailable"
                        )
                }
              </ha-alert>
            `
          : ""
      }
      ${
        this._error
          ? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
          : ""
      }
      <div class="form container">
        <entity-registry-settings-editor
          .hass=${this.hass}
          .entry=${this.entry}
          .helperConfigEntry=${this._helperConfigEntry}
          .disabled=${!!this._submitting}
        ></entity-registry-settings-editor>
      </div>
      <div class="buttons">
        <ha-button
          variant="danger"
          appearance="plain"
          @click=${this._confirmDeleteEntry}
          .disabled=${
            this._submitting ||
            (!this._helperConfigEntry && !stateObj?.attributes.restored)
          }
        >
          ${this.hass.localize("ui.dialogs.entity_registry.editor.delete")}
        </ha-button>
        <ha-button
          @click=${this._updateEntry}
          .disabled=${!this._dirtyState?.isDirty || !!this._submitting}
          .loading=${!!this._submitting}
        >
          ${this.hass.localize("ui.dialogs.entity_registry.editor.update")}
        </ha-button>
      </div>
    `;
  }

  private _openDeviceSettings() {
    const device = this.hass.devices[this.entry.device_id!];

    showDeviceRegistryDetailDialog(this, {
      device: device,
      updateEntry: async (updates) => {
        await updateDeviceRegistryEntry(this.hass, device.id, updates);
      },
    });
  }

  private async _enableEntry() {
    this._error = undefined;
    this._submitting = true;
    try {
      const result = await updateEntityRegistryEntry(
        this.hass!,
        this.entry.entity_id,
        { disabled_by: null }
      );
      fireEvent(this, "entity-entry-updated", result.entity_entry);
      if (result.require_restart) {
        showAlertDialog(this, {
          text: this.hass.localize(
            "ui.dialogs.entity_registry.editor.enabled_restart_confirm"
          ),
        });
      }
      if (result.reload_delay) {
        showAlertDialog(this, {
          text: this.hass.localize(
            "ui.dialogs.entity_registry.editor.enabled_delay_confirm",
            { delay: result.reload_delay }
          ),
        });
      }
    } catch (err: any) {
      this._error = err.message;
    } finally {
      this._submitting = false;
    }
  }

  private async _updateEntry(): Promise<void> {
    this._submitting = true;
    this._error = undefined;
    try {
      const result = await this._registryEditor!.updateEntry();
      this._dirtyState?.markClean();
      if (result.close) {
        fireEvent(this, "close-dialog");
      }
    } catch (err: any) {
      this._error = err.message || "Unknown error";
    } finally {
      this._submitting = false;
    }
  }

  private async _confirmDeleteEntry(): Promise<void> {
    let name = computeEntityEntryName(this.entry, this.hass.devices);
    if (!name) {
      const { device } = getEntityEntryContext(
        this.entry,
        this.hass.entities,
        this.hass.devices,
        this.hass.areas,
        this.hass.floors
      );
      if (device) {
        name = computeDeviceName(device);
      }
    }

    const confirmationText = await getDeleteConfirmationText(
      this.hass,
      this.entry,
      name
    );

    if (
      !(await showConfirmationDialog(this, {
        title: this.hass.localize(
          "ui.dialogs.entity_registry.editor.confirm_delete_title"
        ),
        text: confirmationText,
        confirmText: this.hass.localize("ui.common.delete"),
        dismissText: this.hass.localize("ui.common.cancel"),
        destructive: true,
      }))
    ) {
      return;
    }

    this._submitting = true;

    try {
      if (this._helperConfigEntry) {
        await deleteConfigEntry(this.hass, this._helperConfigEntry.entry_id);
      } else {
        await removeEntityRegistryEntry(this.hass!, this.entry.entity_id);
      }
      fireEvent(this, "close-dialog");
    } finally {
      this._submitting = false;
    }
  }

  static get styles(): CSSResultGroup {
    return [
      haStyle,
      css`
        :host {
          display: block;
        }
        .container {
          padding: var(--ha-space-2) var(--ha-space-6) var(--ha-space-5)
            var(--ha-space-6);
        }
        .buttons {
          box-sizing: border-box;
          display: flex;
          padding: var(--ha-space-4);
          justify-content: space-between;
          padding-bottom: max(var(--safe-area-inset-bottom), var(--ha-space-4));
          background-color: var(--mdc-theme-surface, #fff);
          border-top: 1px solid var(--divider-color);
          position: sticky;
          bottom: 0px;
        }
        ha-alert ha-button {
          width: max-content;
        }
      `,
    ];
  }
}

declare global {
  interface HTMLElementTagNameMap {
    "entity-registry-settings": EntityRegistrySettings;
  }
  interface HASSDomEvents {
    "entity-entry-updated": ExtEntityRegistryEntry;
  }
}
