import { consume, provide, type ContextType } from "@lit/context";
import {
  mdiAlert,
  mdiCheckCircle,
  mdiCloseCircle,
  mdiSkipNext,
  mdiStethoscope,
  mdiSync,
} from "@mdi/js";
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
import type { CSSResultGroup } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import "../../../../../../components/ha-button";
import type { HaButton } from "../../../../../../components/ha-button";
import "../../../../../../components/ha-dialog";
import "../../../../../../components/ha-dialog-footer";
import "../../../../../../components/animation/ha-fade-in";
import "../../../../../../components/ha-spinner";
import "../../../../../../components/progress/ha-progress-bar";
import {
  connectionContext,
  internationalizationContext,
} from "../../../../../../data/context";
import type {
  ZWaveJSNetwork,
  ZWaveJSRebuildRoutesStatusMessage,
} from "../../../../../../data/zwave_js";
import {
  fetchZwaveNetworkStatus,
  rebuildZwaveNetworkRoutes,
  stopRebuildingZwaveNetworkRoutes,
  subscribeRebuildZwaveNetworkRoutesProgress,
} from "../../../../../../data/zwave_js";
import { DialogMixin } from "../../../../../../dialogs/dialog-mixin";
import {
  zwaveJsRebuildNetworkRoutesProgressContext,
  type ZWaveJSRebuildNetworkRoutesProgress,
} from "./context";
import type { ZWaveJSRebuildNetworkRoutesDialogParams } from "./show-dialog-zwave_js-rebuild-network-routes";
import { showZWaveJSRebuildNetworkRoutesDetailDialog } from "./show-dialog-zwave_js-rebuild-network-routes-detail";

@customElement("dialog-zwave_js-rebuild-network-routes")
class DialogZWaveJSRebuildNetworkRoutes extends DialogMixin<ZWaveJSRebuildNetworkRoutesDialogParams>(
  LitElement
) {
  @state()
  @consume({ context: internationalizationContext, subscribe: true })
  private _i18n!: ContextType<typeof internationalizationContext>;

  @state()
  @consume({ context: connectionContext, subscribe: true })
  private _connection!: ContextType<typeof connectionContext>;

  @provide({ context: zwaveJsRebuildNetworkRoutesProgressContext })
  @state()
  private _progress?: ZWaveJSRebuildNetworkRoutesProgress;

  @state() private _status?:
    "ready" | "started" | "failed" | "finished" | "cancelled";

  private _subscribed?: Promise<UnsubscribeFunc>;

  connectedCallback() {
    super.connectedCallback();
    if (this.params?.entry_id) {
      this._fetchData();
    }
  }

  protected render() {
    if (!this.params || !this.params.entry_id) {
      return nothing;
    }

    return html`
      <ha-dialog
        open
        header-title=${this._i18n.localize(
          "ui.panel.config.zwave_js.rebuild_network_routes.title"
        )}
      >
        ${
          !this._status
            ? html`
                <ha-fade-in .delay=${500}
                  ><ha-spinner size="large"></ha-spinner
                ></ha-fade-in>
              `
            : this._status === "ready"
              ? html`
                  <div class="flex-container">
                    <ha-svg-icon
                      .path=${mdiStethoscope}
                      class="status-icon introduction"
                    ></ha-svg-icon>
                    <div class="status">
                      <p>
                        ${this._i18n.localize(
                          "ui.panel.config.zwave_js.rebuild_network_routes.introduction"
                        )}
                      </p>
                    </div>
                  </div>
                  <p>
                    <em>
                      ${this._i18n.localize(
                        "ui.panel.config.zwave_js.rebuild_network_routes.traffic_warning"
                      )}
                    </em>
                  </p>
                `
              : this._status === "started"
                ? html`
                    <div class="status">
                      <p>
                        <b>
                          ${this._i18n.localize(
                            "ui.panel.config.zwave_js.rebuild_network_routes.in_progress"
                          )}
                        </b>
                      </p>
                      <p>
                        ${this._i18n.localize(
                          "ui.panel.config.zwave_js.rebuild_network_routes.run_in_background"
                        )}
                      </p>
                    </div>
                    <ha-progress-bar
                      loading
                      .indeterminate=${!this._progress}
                      .value=${
                        this._progress
                          ? this._progressPercent(this._progress)
                          : undefined
                      }
                    >
                    </ha-progress-bar>
                    ${
                      this._progress
                        ? html` <div class="progress-detail">
                            <ha-button
                              .progressType=${"pending"}
                              @click=${this._showProgressDetail}
                              appearance="outlined"
                              variant="warning"
                              size="s"
                              .title=${this._i18n.localize(
                                "ui.panel.config.zwave_js.rebuild_network_routes.progress.in_progress",
                                { count: this._progress.pending.length }
                              )}
                            >
                              ${this._progress.pending.length}
                              <ha-svg-icon
                                .path=${mdiSync}
                                slot="end"
                              ></ha-svg-icon>
                            </ha-button>
                            <ha-button
                              .progressType=${"done"}
                              @click=${this._showProgressDetail}
                              appearance="outlined"
                              variant="success"
                              size="s"
                              .title=${this._i18n.localize(
                                "ui.panel.config.zwave_js.rebuild_network_routes.progress.completed",
                                { count: this._progress.done.length }
                              )}
                            >
                              ${this._progress.done.length}
                              <ha-svg-icon
                                .path=${mdiCheckCircle}
                                slot="end"
                              ></ha-svg-icon>
                            </ha-button>

                            ${
                              this._progress.failed.length
                                ? html`<ha-button
                                    .progressType=${"failed"}
                                    @click=${this._showProgressDetail}
                                    appearance="outlined"
                                    variant="danger"
                                    size="s"
                                    .title=${this._i18n.localize(
                                      "ui.panel.config.zwave_js.rebuild_network_routes.progress.failed",
                                      { count: this._progress.failed.length }
                                    )}
                                  >
                                    ${this._progress.failed.length}
                                    <ha-svg-icon
                                      .path=${mdiAlert}
                                      slot="end"
                                    ></ha-svg-icon>
                                  </ha-button>`
                                : nothing
                            }
                            ${
                              this._progress.skipped.length
                                ? html`<ha-button
                                    .progressType=${"skipped"}
                                    @click=${this._showProgressDetail}
                                    appearance="outlined"
                                    variant="neutral"
                                    size="s"
                                    .title=${this._i18n.localize(
                                      "ui.panel.config.zwave_js.rebuild_network_routes.progress.skipped",
                                      { count: this._progress.skipped.length }
                                    )}
                                  >
                                    ${this._progress.skipped.length}
                                    <ha-svg-icon
                                      .path=${mdiSkipNext}
                                      slot="end"
                                    ></ha-svg-icon>
                                  </ha-button>`
                                : nothing
                            }
                          </div>`
                        : nothing
                    }
                  `
                : this._status === "failed"
                  ? html`
                      <div class="flex-container">
                        <ha-svg-icon
                          .path=${mdiCloseCircle}
                          class="status-icon failed"
                        ></ha-svg-icon>
                        <div class="status">
                          <p>
                            ${this._i18n.localize(
                              "ui.panel.config.zwave_js.rebuild_network_routes.rebuilding_routes_failed"
                            )}
                          </p>
                        </div>
                      </div>
                    `
                  : this._status === "finished"
                    ? html`
                        <div class="flex-container">
                          <ha-svg-icon
                            .path=${mdiCheckCircle}
                            class="status-icon success"
                          ></ha-svg-icon>
                          <div class="status">
                            <p>
                              ${this._i18n.localize(
                                "ui.panel.config.zwave_js.rebuild_network_routes.rebuilding_routes_complete"
                              )}
                            </p>
                          </div>
                        </div>
                      `
                    : this._status === "cancelled"
                      ? html`
                          <div class="flex-container">
                            <ha-svg-icon
                              .path=${mdiCloseCircle}
                              class="status-icon failed"
                            ></ha-svg-icon>
                            <div class="status">
                              <p>
                                ${this._i18n.localize(
                                  "ui.panel.config.zwave_js.rebuild_network_routes.rebuilding_routes_cancelled"
                                )}
                              </p>
                            </div>
                          </div>
                        `
                      : nothing
        }
        <ha-dialog-footer slot="footer">
          ${
            this._status === "ready"
              ? html`
                  <ha-button
                    slot="primaryAction"
                    @click=${this._startRebuildingRoutes}
                  >
                    ${this._i18n.localize(
                      "ui.panel.config.zwave_js.rebuild_network_routes.start_rebuilding_routes"
                    )}
                  </ha-button>
                `
              : this._status === "started"
                ? html`
                    <ha-button
                      slot="secondaryAction"
                      appearance="plain"
                      @click=${this._stopRebuildingRoutes}
                      variant="danger"
                    >
                      ${this._i18n.localize(
                        "ui.panel.config.zwave_js.rebuild_network_routes.stop_rebuilding_routes"
                      )}
                    </ha-button>
                    <ha-button slot="primaryAction" @click=${this.closeDialog}>
                      ${this._i18n.localize("ui.common.close")}
                    </ha-button>
                  `
                : html`
                    <ha-button slot="primaryAction" @click=${this.closeDialog}>
                      ${this._i18n.localize("ui.common.close")}
                    </ha-button>
                  `
          }
        </ha-dialog-footer>
      </ha-dialog>
    `;
  }

  private async _fetchData(): Promise<void> {
    const network: ZWaveJSNetwork = await fetchZwaveNetworkStatus(
      this._connection.connection,
      {
        entry_id: this.params!.entry_id,
      }
    );
    if (network.controller.is_rebuilding_routes) {
      this._status = "started";
      this._startSubscribingToProgress();
    } else {
      this._status = "ready";
    }
  }

  private _startRebuildingRoutes(): void {
    rebuildZwaveNetworkRoutes(
      this._connection.connection,
      this.params!.entry_id
    );
    this._status = "started";
    this._startSubscribingToProgress();
  }

  private async _startSubscribingToProgress() {
    this._subscribed = subscribeRebuildZwaveNetworkRoutesProgress(
      this._connection.connection,
      this.params!.entry_id,
      this._handleMessage
    );
  }

  private _stopRebuildingRoutes(): void {
    stopRebuildingZwaveNetworkRoutes(
      this._connection.connection,
      this.params!.entry_id
    );
    this._unsubscribe();
    this._status = "cancelled";
  }

  private _handleMessage = (message: ZWaveJSRebuildRoutesStatusMessage) => {
    if (message.event === "rebuild routes progress") {
      const progressNumbers: ZWaveJSRebuildNetworkRoutesProgress = {
        pending: [],
        skipped: [],
        done: [],
        failed: [],
      };

      for (const [nodeId, status] of Object.entries(
        message.rebuild_routes_status
      )) {
        progressNumbers[status].push(Number(nodeId));
      }
      this._progress = progressNumbers;
    }
    if (message.event === "rebuild routes done") {
      this._unsubscribe();
      this._status = "finished";
    }
  };

  private _progressPercent = memoizeOne(
    (progress: ZWaveJSRebuildNetworkRoutesProgress) => {
      const done =
        progress.done.length + progress.skipped.length + progress.failed.length;
      const total = done + progress.pending.length;
      return total > 0 ? (done / total) * 100 : 0;
    }
  );

  private _showProgressDetail(ev: Event) {
    const button = ev.target as HaButton & {
      progressType: "pending" | "skipped" | "failed" | "done";
    };
    showZWaveJSRebuildNetworkRoutesDetailDialog(this, {
      type: button.progressType,
      configEntryId: this.params!.entry_id,
    });
  }

  private _unsubscribe(): void {
    if (this._subscribed) {
      this._subscribed.then((unsub) => unsub());
      this._subscribed = undefined;
    }
  }

  disconnectedCallback(): void {
    super.disconnectedCallback();
    this._unsubscribe();
  }

  static get styles(): CSSResultGroup {
    return [
      css`
        .success {
          color: var(--success-color);
        }

        .failed {
          color: var(--error-color);
        }

        .flex-container {
          display: flex;
          align-items: center;
        }

        ha-svg-icon.status-icon {
          width: 68px;
          height: 48px;
        }

        ha-svg-icon.introduction {
          color: var(--primary-color);
        }

        .flex-container ha-svg-icon {
          margin-right: 20px;
          margin-inline-end: 20px;
          margin-inline-start: initial;
        }

        ha-progress-bar {
          margin-top: var(--ha-space-8);
        }

        .progress-detail {
          margin-top: var(--ha-space-4);
          display: flex;
          justify-content: flex-end;
          flex-wrap: wrap;
          gap: var(--ha-space-3);
        }

        .progress-detail ha-button {
          --ha-font-weight-medium: var(--ha-font-weight-normal);
        }
        .progress-detail ha-button::part(label) {
          white-space: nowrap;
        }
      `,
    ];
  }
}

declare global {
  interface HTMLElementTagNameMap {
    "dialog-zwave_js-rebuild-network-routes": DialogZWaveJSRebuildNetworkRoutes;
  }
}
