/**
 * <plugin-config> - Plugin configuration panel with live apply.
 *
 * Displays plugin configuration for a selected router or entry.
 * Every field change immediately calls /apply for runtime effect.
 * Emits "config-applied" after each apply call.
 */

class PluginConfig extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: "open" });
    this._pluginSignatures = {};
    this._currentType = null;
    this._currentPath = "";
    this._currentName = "";
    this._currentPluginInfo = {};
    this.shadowRoot.innerHTML = `
      <style>
        :host { display: block; }
        .placeholder {
          height: 100%;
          display: flex;
          align-items: center;
          justify-content: center;
          color: #94a3b8;
          font-size: 1.1rem;
        }
        .header {
          margin-bottom: 16px;
          padding-bottom: 12px;
          border-bottom: 2px solid #e0e0e0;
        }
        .header h2 { font-size: 1.1rem; color: #333; margin: 0; }
        .header .path { color: #666; font-size: 0.85rem; margin-top: 4px; }
        .header .node-type {
          display: inline-block;
          padding: 2px 8px;
          border-radius: 4px;
          font-size: 0.75rem;
          font-weight: 600;
          margin-right: 8px;
        }
        .type-router { background: #e3f2fd; color: #1565c0; }
        .type-entry { background: #f3e5f5; color: #7b1fa2; }
        .plugin-section {
          margin-bottom: 20px;
          border: 1px solid #e0e0e0;
          border-radius: 8px;
          overflow: hidden;
        }
        .plugin-header {
          background: #f5f5f5;
          padding: 10px 16px;
          font-weight: 600;
          font-size: 0.95rem;
          color: #333;
          display: flex;
          align-items: center;
          gap: 8px;
        }
        .plugin-desc {
          font-weight: 400;
          font-size: 0.8rem;
          color: #666;
        }
        .plugin-body { padding: 12px 16px; }
        .config-row {
          display: flex;
          align-items: center;
          gap: 12px;
          margin-bottom: 10px;
        }
        .config-row label {
          min-width: 120px;
          font-size: 0.85rem;
          color: #555;
          font-weight: 500;
        }
        .config-row input[type="text"],
        .config-row input[type="number"] {
          flex: 1;
          padding: 6px 10px;
          border: 1px solid #ccc;
          border-radius: 4px;
          font-size: 0.85rem;
          transition: border-color 0.2s;
        }
        .config-row input:focus {
          outline: none;
          border-color: #1565c0;
        }
        .config-row input[type="checkbox"] {
          width: 18px;
          height: 18px;
          cursor: pointer;
        }
        .config-row input.applied {
          border-color: #2e7d32;
        }
        .config-row input.apply-error {
          border-color: #c62828;
        }
        .target-label {
          font-size: 0.75rem;
          color: #999;
          font-style: italic;
          margin-bottom: 8px;
          margin-top: 8px;
        }
        .no-plugins {
          color: #94a3b8;
          font-size: 0.9rem;
          padding: 20px;
          text-align: center;
        }
      </style>
      <div id="content">
        <div class="placeholder">Select a router or entry from the tree</div>
      </div>
    `;
  }

  setPluginSignatures(signatures) {
    this._pluginSignatures = signatures;
  }

  setNode(type, path, name, pluginInfo) {
    this._currentType = type;
    this._currentPath = path;
    this._currentName = name;
    this._currentPluginInfo = pluginInfo;
    this._render();
  }

  showPlaceholder() {
    this.shadowRoot.getElementById("content").innerHTML =
      `<div class="placeholder">Select a router or entry from the tree</div>`;
  }

  _render() {
    const content = this.shadowRoot.getElementById("content");
    const info = this._currentPluginInfo;
    const pluginNames = Object.keys(info);

    if (pluginNames.length === 0) {
      content.innerHTML = `<div class="no-plugins">No plugins configured on this node</div>`;
      return;
    }

    let html = this._renderHeader();
    for (const pname of pluginNames) {
      html += this._renderPlugin(pname, info[pname]);
    }
    content.innerHTML = html;

    // Bind change events for live apply
    this._bindChangeEvents();
  }

  _bindChangeEvents() {
    const inputs = this.shadowRoot.querySelectorAll("input[data-plugin]:not([disabled])");
    for (const input of inputs) {
      const eventType = input.type === "checkbox" ? "change" : "change";
      input.addEventListener(eventType, () => this._applyField(input));
      // For text/number: also apply on Enter key
      if (input.type === "text" || input.type === "number") {
        input.addEventListener("keydown", (e) => {
          if (e.key === "Enter") this._applyField(input);
        });
      }
    }
  }

  async _applyField(input) {
    const plugin = input.dataset.plugin;
    const target = input.dataset.target;
    const field = input.dataset.field;
    const type = input.dataset.type;

    let value;
    if (type === "bool") {
      value = input.checked;
    } else if (type === "number") {
      value = input.value ? Number(input.value) : 0;
    } else {
      value = input.value;
    }

    try {
      const params = new URLSearchParams({
        router_path: this._currentPath,
        plugin_name: plugin,
        target: target,
        [field]: String(value),
      });
      const res = await fetch(`/_sys/plugin_config/apply?${params}`);
      const data = await res.json();

      if (data.ok) {
        input.classList.add("applied");
        input.classList.remove("apply-error");
        setTimeout(() => input.classList.remove("applied"), 1000);
        this.dispatchEvent(new CustomEvent("config-applied", { detail: { ok: true } }));
      } else {
        input.classList.add("apply-error");
        console.error("Apply error:", data.error);
        this.dispatchEvent(new CustomEvent("config-applied", { detail: { ok: false, error: data.error } }));
      }
    } catch (err) {
      input.classList.add("apply-error");
      console.error("Apply failed:", err);
      this.dispatchEvent(new CustomEvent("config-applied", { detail: { ok: false, error: err.message } }));
    }
  }

  _renderHeader() {
    const typeClass = this._currentType === "router" ? "type-router" : "type-entry";
    const typeLabel = this._currentType === "router" ? "Router" : "Entry";
    const displayName = this._currentType === "entry" ? this._currentName : this._currentPath;
    return `
      <div class="header">
        <h2>
          <span class="node-type ${typeClass}">${typeLabel}</span>
          ${this._esc(displayName)}
        </h2>
        <div class="path">${this._esc(this._currentPath)}</div>
      </div>
    `;
  }

  _renderPlugin(pname, pdata) {
    const sig = this._pluginSignatures[pname] || {};
    const desc = sig.description || "";
    const params = sig.configure_params || [];

    const allConfig = (pdata["_all_"] || {}).config || {};
    const entryConfig = this._currentType === "entry"
      ? ((pdata[this._currentName] || {}).config || {})
      : {};

    let fieldsHtml = "";

    if (this._currentType === "router") {
      fieldsHtml += `<div class="target-label">Router-level config (_all_)</div>`;
      fieldsHtml += this._renderFields(pname, "_all_", params, allConfig);
    } else {
      fieldsHtml += `<div class="target-label">Router default (_all_) - inherited</div>`;
      fieldsHtml += this._renderFields(pname, "_all_", params, allConfig, true);
      fieldsHtml += `<div class="target-label">Entry override: ${this._esc(this._currentName)}</div>`;
      fieldsHtml += this._renderFields(pname, this._currentName, params, entryConfig);
    }

    return `
      <div class="plugin-section">
        <div class="plugin-header">
          ${this._esc(pname)}
          <span class="plugin-desc">${this._esc(desc)}</span>
        </div>
        <div class="plugin-body">
          ${fieldsHtml}
        </div>
      </div>
    `;
  }

  _renderFields(pname, target, params, currentValues, readOnly = false) {
    if (params.length === 0) {
      if (Object.keys(currentValues).length === 0) {
        return `<div style="color:#999;font-size:0.8rem">No configuration</div>`;
      }
      let html = "";
      for (const [key, val] of Object.entries(currentValues)) {
        html += this._renderField(pname, target, key, typeof val, val, readOnly);
      }
      return html;
    }

    let html = "";
    for (const param of params) {
      const value = currentValues[param.name] !== undefined
        ? currentValues[param.name]
        : param.default;
      html += this._renderField(pname, target, param.name, param.type || "str", value, readOnly);
    }
    return html;
  }

  _renderField(pname, target, fieldName, fieldType, value, readOnly) {
    const inputId = `field_${pname}_${target}_${fieldName}`;
    const disabled = readOnly ? "disabled" : "";

    if (fieldType === "bool" || typeof value === "boolean") {
      const checked = value ? "checked" : "";
      return `
        <div class="config-row">
          <label for="${inputId}">${this._esc(fieldName)}</label>
          <input type="checkbox" id="${inputId}"
            data-plugin="${pname}" data-target="${target}" data-field="${fieldName}" data-type="bool"
            ${checked} ${disabled}>
        </div>
      `;
    }

    if (fieldType === "int" || fieldType === "float" || typeof value === "number") {
      return `
        <div class="config-row">
          <label for="${inputId}">${this._esc(fieldName)}</label>
          <input type="number" id="${inputId}"
            data-plugin="${pname}" data-target="${target}" data-field="${fieldName}" data-type="number"
            value="${value !== undefined && value !== null ? value : ""}" ${disabled}>
        </div>
      `;
    }

    return `
      <div class="config-row">
        <label for="${inputId}">${this._esc(fieldName)}</label>
        <input type="text" id="${inputId}"
          data-plugin="${pname}" data-target="${target}" data-field="${fieldName}" data-type="str"
          value="${this._esc(String(value !== undefined && value !== null ? value : ""))}" ${disabled}>
      </div>
    `;
  }

  _esc(str) {
    const div = document.createElement("div");
    div.textContent = str;
    return div.innerHTML;
  }
}

customElements.define("plugin-config", PluginConfig);
