var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __decorateClass = (decorators, target, key, kind) => {
  var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
  for (var i = decorators.length - 1, decorator; i >= 0; i--)
    if (decorator = decorators[i])
      result = (kind ? decorator(target, key, result) : decorator(result)) || result;
  if (kind && result) __defProp(target, key, result);
  return result;
};
/**
 * @license
 * Copyright 2025-2026 Open Home Foundation
 * SPDX-License-Identifier: Apache-2.0
 */
import "@material/web/button/filled-button";
import "@material/web/button/outlined-button";
import "@material/web/button/text-button";
import "@material/web/divider/divider";
import "@material/web/iconbutton/icon-button";
import "@material/web/list/list";
import "@material/web/list/list-item";
import { consume } from "@lit/context";
import { UpdateSource } from "@matter-server/ws-client";
import { mdiChatProcessing, mdiLink, mdiPencil, mdiShareVariant, mdiTrashCan, mdiUpdate, mdiVideo } from "@mdi/js";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators.js";
import { clientContext, tickContext } from "../../client/client-context.js";
import { showAlertDialog, showPromptDialog } from "../../components/dialog-box/show-dialog-box.js";
import { showNodeBindingDialog } from "../../components/dialogs/binding/show-node-binding-dialog.js";
import { showNodeLabelDialog } from "../../components/dialogs/node-label-dialog/show-node-label-dialog.js";
import { handleAsync } from "../../util/async-handler.js";
import "../../components/ha-svg-icon";
import "../camera-overlay.js";
import { getDeviceIcon } from "../../util/device-icons.js";
import { getEndpointDeviceTypes } from "../matter-endpoint-view.js";
import { bindingContext } from "./context.js";
const UPDATE_STATE_LABELS = {
  1: "Idle",
  2: "Querying",
  3: "Waiting (Querying)",
  4: "Downloading",
  5: "Applying",
  6: "Waiting (Applying)",
  7: "Rolling back",
  8: "Waiting for consent"
};
function getUpdateStateLabel(state2, progress) {
  const label = UPDATE_STATE_LABELS[state2] ?? `Unknown (${state2})`;
  if (state2 === 4 && progress !== void 0) {
    return `${label} (${progress}%)`;
  }
  return label;
}
function getNodeDeviceTypes(node) {
  const uniqueEndpoints = new Set(Object.keys(node.attributes).map((key) => Number(key.split("/")[0])));
  const allDeviceTypes = /* @__PURE__ */ new Set();
  uniqueEndpoints.forEach((endpointId) => {
    getEndpointDeviceTypes(node, endpointId).forEach((deviceType) => {
      allDeviceTypes.add(deviceType);
    });
  });
  return Array.from(allDeviceTypes);
}
let NodeDetails = class extends LitElement {
  constructor() {
    super(...arguments);
    this._tick = 0;
    this._updateInitiated = false;
  }
  render() {
    if (!this.node) return html``;
    const bindings = this.node.attributes[this.endpoint + "/30/0"];
    const deviceTypeIds = getEndpointDeviceTypes(this.node, this.endpoint).map((d) => d.id);
    const isCamera = deviceTypeIds.includes(322) || deviceTypeIds.includes(323);
    return html`
            <md-list>
                <md-list-item>
                    <ha-svg-icon slot="start" class="device-icon" .path=${getDeviceIcon(this.node)}></ha-svg-icon>
                    <div slot="headline" class="node-label-row">
                        <b>${this.node.nodeLabel || "Node Info"}</b>
                        ${this.node.available ? html`
                                  <md-icon-button
                                      @click=${() => this._editNodeLabel()}
                                      aria-label="Edit node label"
                                      title="Edit node label"
                                  >
                                      <ha-svg-icon .path=${mdiPencil}></ha-svg-icon>
                                  </md-icon-button>
                              ` : nothing}
                        ${this.node.available ? nothing : html` <span class="status">OFFLINE</span> `}
                    </div>
                </md-list-item>
                <md-list-item>
                    <div slot="supporting-text"><span class="left">VendorName: </span>${this.node.vendorName}</div>
                    <div slot="supporting-text"><span class="left">ProductName: </span>${this.node.productName}</div>
                    <div slot="supporting-text">
                        <span class="left">Commissioned: </span>${this.node.date_commissioned}
                    </div>
                    <div slot="supporting-text">
                        <span class="left">Last interviewed: </span>${this.node.last_interview}
                    </div>
                    <div slot="supporting-text"><span class="left">Is bridge: </span>${this.node.is_bridge}</div>
                    <div slot="supporting-text"><span class="left">Serialnumber: </span>${this.node.serialNumber}</div>
                    ${this.node.matter_version ? html`<div slot="supporting-text">
                              <span class="left">Matter version: </span>${this.node.matter_version}
                          </div>` : nothing}
                    ${this.node.is_bridge ? "" : html` <div slot="supporting-text">
                              <span class="left">All device types: </span>${getNodeDeviceTypes(this.node).map((deviceType) => {
      return deviceType.label;
    }).join(" / ")}
                          </div>`}
                </md-list-item>
                <md-list-item>
                    <div class="btn-row">
                        <md-outlined-button @click=${handleAsync(() => this._reinterview())}
                            >Interview<ha-svg-icon slot="icon" .path=${mdiChatProcessing}></ha-svg-icon
                        ></md-outlined-button>
                        ${this._updateInitiated ? html` <md-outlined-button disabled
                                  >Checking for updates<ha-svg-icon slot="icon" .path=${mdiUpdate}></ha-svg-icon
                              ></md-outlined-button>` : (this.node.updateState ?? 0) > 1 ? html` <md-outlined-button disabled
                                    >${getUpdateStateLabel(
      this.node.updateState,
      this.node.updateStateProgress
    )}<ha-svg-icon slot="icon" .path=${mdiUpdate}></ha-svg-icon
                                ></md-outlined-button>` : html`<md-outlined-button @click=${handleAsync(() => this._searchUpdate())}
                                    >Update<ha-svg-icon slot="icon" .path=${mdiUpdate}></ha-svg-icon
                                ></md-outlined-button>`}
                        ${isCamera ? html`
                                  <md-outlined-button
                                      @click=${() => this._openCameraOverlay()}
                                      ?disabled=${!this.node.available}
                                  >
                                      Live View
                                      <ha-svg-icon slot="icon" .path=${mdiVideo}></ha-svg-icon>
                                  </md-outlined-button>
                              ` : nothing}
                        ${bindings ? html`
                                  <md-outlined-button @click=${handleAsync(() => this._binding())}>
                                      Binding
                                      <ha-svg-icon slot="icon" .path=${mdiLink}></ha-svg-icon>
                                  </md-outlined-button>
                              ` : nothing}

                        <md-outlined-button @click=${handleAsync(() => this._openCommissioningWindow())}
                            >Share<ha-svg-icon slot="icon" .path=${mdiShareVariant}></ha-svg-icon
                        ></md-outlined-button>
                        <md-outlined-button @click=${handleAsync(() => this._remove())}
                            >Remove<ha-svg-icon slot="icon" .path=${mdiTrashCan}></ha-svg-icon
                        ></md-outlined-button>
                    </div>
                </md-list-item>
            </md-list>
        `;
  }
  _editNodeLabel() {
    showNodeLabelDialog(this.client, this.node);
  }
  async _reinterview() {
    if (!await showPromptDialog({
      title: "Reinterview",
      text: "Are you sure you want to reinterview this node?",
      confirmText: "Reinterview"
    })) {
      return;
    }
    try {
      await this.client.interviewNode(this.node.node_id);
      showAlertDialog({
        title: "Reinterview node",
        text: "Success!"
      });
      location.hash = "#";
    } catch (err) {
      showAlertDialog({
        title: "Failed to reinterview node",
        text: err.message
      });
    }
  }
  async _remove() {
    if (!await showPromptDialog({
      title: "Remove",
      text: "Are you sure you want to remove this node?",
      confirmText: "Remove"
    })) {
      return;
    }
    try {
      await this.client.removeNode(this.node.node_id);
      location.replace("#");
    } catch (err) {
      showAlertDialog({
        title: "Failed to remove node",
        text: err.message
      });
    }
  }
  async _binding() {
    try {
      showNodeBindingDialog(this.node, this.endpoint);
    } catch (err) {
      console.error("Binding error:", err);
    }
  }
  _openCameraOverlay() {
    const overlay = document.createElement("camera-overlay");
    overlay.nodeId = this.node.node_id;
    overlay.endpointId = this.endpoint;
    const root = document.querySelector("matter-dashboard-app");
    if (root) {
      root.renderRoot.appendChild(overlay);
    } else {
      document.body.appendChild(overlay);
    }
  }
  async _searchUpdate() {
    const nodeUpdate = await this.client.checkNodeUpdate(this.node.node_id);
    if (!nodeUpdate) {
      showAlertDialog({
        title: "No update available",
        text: "No update available for this node"
      });
      return;
    }
    const isUnverifiedSource = nodeUpdate.update_source !== UpdateSource.MAIN_NET_DCL;
    if (!await showPromptDialog({
      title: "Firmware update available",
      text: html`Found a firmware update for this node on <b>${nodeUpdate.update_source}</b>.
                    ${isUnverifiedSource ? html`
                              <p
                                  style="
                                          background: var(--md-sys-color-error, #b3261e);
                                          color: var(--md-sys-color-on-error, #fff);
                                          padding: 8px 12px;
                                          border-radius: 4px;
                                          font-weight: bold;
                                      "
                              >
                                  Warning: This update was found on an unverified source. Updates from test-net or local
                                  sources have not been certified and may contain untested firmware that could result in
                                  non-functional devices. Applying these updates is entirely at your own risk.
                              </p>
                          ` : nothing}
                    <p>
                        Do you want to update this node to version
                        <b>${nodeUpdate.software_version_string}</b>?
                    </p>
                    <p>
                        Note that updating firmware is at your own risk and may cause the device to malfunction or needs
                        additional handling such as power cycling it and/or recommissioning it. Use with care.
                    </p>
                    ${nodeUpdate.firmware_information ? html`<p>${nodeUpdate.firmware_information}</p>` : nothing}`,
      confirmText: "Start Update"
    })) {
      return;
    }
    try {
      this._updateInitiated = true;
      await this.client.updateNode(this.node.node_id, nodeUpdate.software_version);
    } catch (err) {
      showAlertDialog({
        title: "Failed to update node",
        text: err.message
      });
    } finally {
      this._updateInitiated = false;
    }
  }
  async _openCommissioningWindow() {
    if (!await showPromptDialog({
      title: "Share device",
      text: "Do you want to share this device with another Matter controller (open commissioning window)?",
      confirmText: "Share"
    })) {
      return;
    }
    try {
      const shareCode = await this.client.openCommissioningWindow(this.node.node_id);
      showAlertDialog({
        title: "Share device",
        text: `Setup code: ${shareCode.setup_manual_code}`
      });
    } catch (err) {
      showAlertDialog({
        title: "Failed to open commissioning window on node",
        text: err.message
      });
    }
  }
};
NodeDetails.styles = css`
        .node-label-row {
            display: flex;
            align-items: center;
            gap: 8px;
        }

        .node-label-row md-icon-button {
            width: 24px;
            height: 24px;
            --md-icon-button-state-layer-width: 32px;
            --md-icon-button-state-layer-height: 32px;
        }

        .device-icon {
            --icon-primary-color: var(--md-sys-color-on-surface-variant, #666);
        }

        .btn-row {
            --md-outlined-button-container-shape: 0px;
            display: flex;
            flex-wrap: wrap;
            gap: 8px;
        }

        .btn-row md-outlined-button {
            max-width: 100%;
        }

        .left {
            min-width: 120px;
            display: inline-block;
        }

        @media (min-width: 600px) {
            .left {
                min-width: 150px;
            }
        }

        .whitespace {
            height: 15px;
        }

        .status {
            color: var(--danger-color);
            font-weight: bold;
            font-size: 0.8em;
        }
    `;
__decorateClass([
  consume({ context: clientContext })
], NodeDetails.prototype, "client", 2);
__decorateClass([
  consume({ context: tickContext, subscribe: true })
], NodeDetails.prototype, "_tick", 2);
__decorateClass([
  property()
], NodeDetails.prototype, "node", 2);
__decorateClass([
  state()
], NodeDetails.prototype, "_updateInitiated", 2);
__decorateClass([
  consume({ context: bindingContext })
], NodeDetails.prototype, "endpoint", 2);
NodeDetails = __decorateClass([
  customElement("node-details")
], NodeDetails);
export {
  NodeDetails
};
//# sourceMappingURL=node-details.js.map
