document.addEventListener("DOMContentLoaded", () => {
  const output = document.getElementById("console");
  const triggerType = document.getElementById("trigger_type");
  const scheduleKind = document.getElementById("schedule_kind");
  const addCommandButton = document.getElementById("add-command-step");
  const commandSteps = document.getElementById("command-steps");
  const nodeLive = document.querySelector(".node-live");
  const dashboardNodes = document.getElementById("dashboard-nodes");
  const dashboardSearch = document.getElementById("dashboard-search");
  const authToggle = document.querySelector("[data-auth-toggle]");
  const themeRadios = document.querySelectorAll('input[name="theme"]');
  const themeModeInput = document.querySelector('input[name="mode"]');
  const uptimeChart = document.getElementById("uptime-chart");
  const commandLogModal = document.getElementById("commandLogModal");
  const updatePackagesModal = document.getElementById("updatePackagesModal");
  const editGroupModal = document.getElementById("editGroupModal");
  const groupIconPickerModal = document.getElementById("groupIconPickerModal");
  const groupIconSearch = document.querySelector("[data-group-icon-search]");
  const groupIconGrid = document.querySelector("[data-group-icon-grid]");
  let activeGroupIconInput = null;
  let activeGroupIconPreview = "";

  const setGroupIconPreview = (previewId, iconClass) => {
    const preview = document.getElementById(previewId);
    if (!(preview instanceof HTMLElement)) {
      return;
    }
    preview.innerHTML = `<i class="${iconClass}"></i>`;
  };

  const highlightSelectedGroupIcon = (iconClass) => {
    groupIconGrid?.querySelectorAll("[data-icon-option]").forEach((option) => {
      if (option instanceof HTMLElement) {
        option.classList.toggle("is-active", option.dataset.iconOption === iconClass);
      }
    });
  };

  const attachXtermConsole = (consoleOutput) => {
    const wsPath = consoleOutput.dataset.ws;
    if (!wsPath || typeof Terminal === "undefined") {
      return;
    }

    const term = new Terminal({
      cursorBlink: true,
      convertEol: true,
      fontFamily: '"Cascadia Code", "SFMono-Regular", Consolas, "Liberation Mono", monospace',
      fontSize: 14,
      lineHeight: 1.25,
      theme: {
        background: "#0b1220",
        foreground: "#dbeafe",
        cursor: "#93c5fd",
        cursorAccent: "#0b1220",
        selectionBackground: "rgba(147, 197, 253, 0.28)",
      },
    });
    const fitAddon = typeof FitAddon !== "undefined" ? new FitAddon.FitAddon() : null;
    if (fitAddon) {
      term.loadAddon(fitAddon);
    }
    term.open(consoleOutput);

    const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
    const socket = new WebSocket(`${protocol}//${window.location.host}${wsPath}`);
    const fit = () => {
      fitAddon?.fit();
      term.focus();
    };

    window.setTimeout(fit, 0);
    window.addEventListener("resize", fit);
    if (typeof ResizeObserver !== "undefined") {
      const observer = new ResizeObserver(fit);
      observer.observe(consoleOutput);
    }

    socket.addEventListener("message", (event) => {
      term.write(event.data);
    });

    socket.addEventListener("open", () => {
      fit();
    });

    socket.addEventListener("close", () => {
      term.write("\r\n[session closed]\r\n");
    });

    socket.addEventListener("error", () => {
      term.write("\r\n[connection error]\r\n");
    });

    term.onData((value) => {
      if (socket.readyState === WebSocket.OPEN) {
        socket.send(value);
      }
    });
  };

  if (output?.dataset.xterm === "true") {
    attachXtermConsole(output);
  }

  if (commandLogModal instanceof HTMLElement) {
    commandLogModal.addEventListener("show.bs.modal", (event) => {
      const trigger = event.relatedTarget;
      if (!(trigger instanceof HTMLElement)) {
        return;
      }

      const target = trigger.dataset.logTarget || "";
      const time = trigger.dataset.logTime || "";
      const status = trigger.dataset.logStatus || "";
      const duration = trigger.dataset.logDuration || "";
      const command = trigger.dataset.logCommand || "";
      const outputText = trigger.dataset.logOutput || "";

      const meta = commandLogModal.querySelector("[data-command-log-meta]");
      const commandNode = commandLogModal.querySelector("[data-command-log-command]");
      const outputNode = commandLogModal.querySelector("[data-command-log-output]");

      if (meta) {
        meta.textContent = [target, time, status, duration].filter(Boolean).join(" · ");
      }
      if (commandNode) {
        commandNode.textContent = command || "-";
      }
      if (outputNode) {
        outputNode.textContent = outputText || "No output";
      }
    });
  }

  if (updatePackagesModal instanceof HTMLElement) {
    updatePackagesModal.addEventListener("show.bs.modal", (event) => {
      const trigger = event.relatedTarget;
      if (!(trigger instanceof HTMLElement)) {
        return;
      }

      const nodeName = trigger.dataset.nodeName || "";
      const packageCount = trigger.dataset.packageCount || "0";
      const rawPackages = trigger.dataset.packages || "[]";
      const nodeLabel = updatePackagesModal.querySelector("[data-update-packages-node]");
      const body = updatePackagesModal.querySelector("[data-update-packages-body]");
      const countValue = Number.parseInt(packageCount, 10);
      const countLabel = Number.isFinite(countValue) && countValue === 1 ? "1 pending package" : `${packageCount} pending packages`;

      if (nodeLabel) {
        nodeLabel.textContent = `${nodeName} · ${countLabel}`;
      }

      if (!(body instanceof HTMLElement)) {
        return;
      }

      let packages = [];
      try {
        packages = JSON.parse(rawPackages);
      } catch (_) {
        packages = [];
      }

      if (!Array.isArray(packages) || packages.length === 0) {
        body.innerHTML = `<tr><td colspan="4" class="text-body-secondary text-center py-4">No pending packages.</td></tr>`;
        return;
      }

      body.innerHTML = packages.map((pkg) => `
        <tr>
          <td class="fw-semibold">${pkg.Name || "-"}</td>
          <td class="text-body-secondary">${pkg.Current || "-"}</td>
          <td>${pkg.Available || "-"}</td>
          <td class="text-body-secondary">${pkg.Architecture || "-"}</td>
        </tr>
      `).join("");
    });
  }

  if (editGroupModal instanceof HTMLElement) {
    editGroupModal.addEventListener("show.bs.modal", (event) => {
      const trigger = event.relatedTarget;
      if (!(trigger instanceof HTMLElement)) {
        return;
      }

      const groupId = trigger.dataset.groupId || "";
      const groupName = trigger.dataset.groupName || "";
      const groupDescription = trigger.dataset.groupDescription || "";
      const groupIcon = trigger.dataset.groupIcon || "ti ti-stack-2";
      const form = editGroupModal.querySelector("[data-edit-group-form]");
      const nameInput = editGroupModal.querySelector("[data-edit-group-name]");
      const descriptionInput = editGroupModal.querySelector("[data-edit-group-description]");
      const iconInput = document.getElementById("editGroupIconValue");
      const iconTrigger = editGroupModal.querySelector("[data-edit-group-icon-trigger]");

      if (form instanceof HTMLFormElement) {
        form.action = `/groups/${groupId}`;
      }
      if (nameInput instanceof HTMLInputElement) {
        nameInput.value = groupName;
      }
      if (descriptionInput instanceof HTMLTextAreaElement) {
        descriptionInput.value = groupDescription;
      }
      if (iconInput instanceof HTMLInputElement) {
        iconInput.value = groupIcon;
      }
      setGroupIconPreview("editGroupIconPreview", groupIcon);
      if (iconTrigger instanceof HTMLElement) {
        iconTrigger.dataset.iconValue = groupIcon;
      }
    });
  }

  if (groupIconPickerModal instanceof HTMLElement) {
    groupIconPickerModal.addEventListener("show.bs.modal", (event) => {
      const trigger = event.relatedTarget;
      if (!(trigger instanceof HTMLElement)) {
        return;
      }

      activeGroupIconInput = document.getElementById(trigger.dataset.iconInput || "");
      activeGroupIconPreview = trigger.dataset.iconPreview || "";
      const currentValue = trigger.dataset.iconValue || (activeGroupIconInput instanceof HTMLInputElement ? activeGroupIconInput.value : "ti ti-stack-2");

      if (groupIconSearch instanceof HTMLInputElement) {
        groupIconSearch.value = "";
      }
      groupIconGrid?.querySelectorAll("[data-icon-option]").forEach((option) => {
        if (option instanceof HTMLElement) {
          option.classList.remove("d-none");
        }
      });
      highlightSelectedGroupIcon(currentValue);
      window.setTimeout(() => groupIconSearch?.focus(), 120);
    });

    groupIconGrid?.addEventListener("click", (event) => {
      const target = event.target;
      if (!(target instanceof Element)) {
        return;
      }
      const option = target.closest("[data-icon-option]");
      if (!(option instanceof HTMLElement) || !(activeGroupIconInput instanceof HTMLInputElement)) {
        return;
      }

      const iconClass = option.dataset.iconOption || "ti ti-stack-2";
      activeGroupIconInput.value = iconClass;
      if (activeGroupIconPreview) {
        setGroupIconPreview(activeGroupIconPreview, iconClass);
      }
      document.querySelectorAll(`[data-icon-input="${activeGroupIconInput.id}"]`).forEach((trigger) => {
        if (trigger instanceof HTMLElement) {
          trigger.dataset.iconValue = iconClass;
        }
      });
      highlightSelectedGroupIcon(iconClass);
      bootstrap.Modal.getInstance(groupIconPickerModal)?.hide();
    });

    groupIconSearch?.addEventListener("input", () => {
      const query = groupIconSearch.value.trim().toLowerCase();
      groupIconGrid?.querySelectorAll("[data-icon-option]").forEach((option) => {
        if (!(option instanceof HTMLElement)) {
          return;
        }
        const label = option.dataset.iconOption || "";
        option.classList.toggle("d-none", query !== "" && !label.toLowerCase().includes(query));
      });
    });
  }

  const syncScheduleUi = () => {
    if (!triggerType || !scheduleKind) {
      return;
    }

    const schedulePanel = document.querySelector(".schedule-panel");
    const weeklyRows = document.querySelectorAll(".weekly-only");
    const intervalRows = document.querySelectorAll(".interval-only");
    const showSchedule = triggerType.value !== "triggered";
    const showWeekly = showSchedule && scheduleKind.value === "weekly";
    const showInterval = showSchedule && scheduleKind.value === "interval";

    if (schedulePanel) {
      schedulePanel.classList.toggle("opacity-50", !showSchedule);
    }
    weeklyRows.forEach((row) => row.classList.toggle("d-none", !showWeekly));
    intervalRows.forEach((row) => row.classList.toggle("d-none", !showInterval));
  };

  triggerType?.addEventListener("change", syncScheduleUi);
  scheduleKind?.addEventListener("change", syncScheduleUi);
  syncScheduleUi();

  addCommandButton?.addEventListener("click", () => {
    if (!commandSteps) {
      return;
    }

    const nextIndex = commandSteps.querySelectorAll(".command-step").length + 1;
    const wrapper = document.createElement("div");
    wrapper.className = "input-group command-step";
    wrapper.innerHTML = `
      <span class="input-group-text">${nextIndex}</span>
      <input type="text" class="form-control" name="command_steps[]" placeholder="command ${nextIndex}" required>
      <button class="btn btn-outline-danger remove-command-step" type="button">Remove</button>
    `;
    commandSteps.appendChild(wrapper);
  });

  commandSteps?.addEventListener("click", (event) => {
    const target = event.target;
    if (!(target instanceof HTMLElement) || !target.classList.contains("remove-command-step")) {
      return;
    }

    const steps = commandSteps.querySelectorAll(".command-step");
    if (steps.length <= 1) {
      return;
    }

    target.closest(".command-step")?.remove();
    commandSteps.querySelectorAll(".command-step").forEach((step, index) => {
      const badge = step.querySelector(".input-group-text");
      if (badge) {
        badge.textContent = String(index + 1);
      }
    });
  });

  if (nodeLive instanceof HTMLElement) {
    const nodeId = nodeLive.dataset.nodeId;
    const history = {
      cpu: [],
      ram: [],
      disk: [],
      uptime: [],
    };

    const uptimeLabel = (seconds) => {
      const days = Math.floor(seconds / 86400);
      const hours = Math.floor((seconds % 86400) / 3600);
      const minutes = Math.floor((seconds % 3600) / 60);
      if (days > 0) return `${days}d ${hours}h ${minutes}m`;
      return `${hours}h ${minutes}m`;
    };

    const renderSparkline = (values, key) => {
      if (values.length === 0) {
        return "";
      }

      let min = 0;
      let max = 100;

      if (key === "uptime") {
        min = Math.min(...values);
        max = Math.max(...values);
        if (max-min < 5) {
          max = min + 5;
        }
      }

      const path = values.map((value, index) => {
        const x = values.length === 1 ? 0 : (index / (values.length - 1)) * 100;
        const normalized = (value - min) / Math.max(max - min, 1);
        const y = 90 - normalized * 72;
        return `${index === 0 ? "M" : "L"} ${x.toFixed(2)} ${y.toFixed(2)}`;
      }).join(" ");

      return `
        <svg viewBox="0 0 100 100" preserveAspectRatio="none">
          <path d="${path}" fill="none" stroke="rgb(var(--color-primary-500))" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" vector-effect="non-scaling-stroke"></path>
        </svg>
      `;
    };

    const pushValue = (key, value) => {
      history[key].push(value);
      if (history[key].length > 60) {
        history[key].shift();
      }
      const card = nodeLive.querySelector(`.kpi-card[data-kpi="${key}"] .kpi-graph`);
      if (card) {
        card.innerHTML = renderSparkline(history[key], key);
      }
    };

    const updateNodeStats = async () => {
      if (!nodeId) {
        return;
      }
      try {
        const response = await fetch(`/nodes/${nodeId}/stats`, { headers: { Accept: "application/json" } });
        if (!response.ok) {
          return;
        }
        const stats = await response.json();
        const cpu = Number(stats.cpu_usage || 0);
        const ram = Number(stats.ram_usage || 0);
        const disk = Number(stats.disk_usage || 0);
        const uptime = Number(stats.uptime_seconds || 0);

        const cpuValue = nodeLive.querySelector('[data-kpi-value="cpu"]');
        const ramValue = nodeLive.querySelector('[data-kpi-value="ram"]');
        const diskValue = nodeLive.querySelector('[data-kpi-value="disk"]');
        const uptimeValue = nodeLive.querySelector('[data-kpi-value="uptime"]');

        if (cpuValue) cpuValue.textContent = `${cpu.toFixed(1)}%`;
        if (ramValue) ramValue.textContent = `${ram.toFixed(1)}%`;
        if (diskValue) diskValue.textContent = `${disk.toFixed(1)}%`;
        if (uptimeValue) uptimeValue.textContent = uptimeLabel(uptime);

        pushValue("cpu", cpu);
        pushValue("ram", ram);
        pushValue("disk", disk);
        pushValue("uptime", Math.min(uptime / 3600, 100));
      } catch (_) {
        // Ignore transient poll failures.
      }
    };

    updateNodeStats();
    window.setInterval(updateNodeStats, 1000);
  }

  if (dashboardNodes instanceof HTMLElement) {
    const url = dashboardNodes.dataset.dashboardNodesUrl;
    if (url) {
      const loadDashboardNodes = async (showErrorState) => {
        try {
          const response = await fetch(url, { headers: { Accept: "text/html" } });
          if (!response.ok) {
            throw new Error("failed");
          }
          const html = await response.text();
          dashboardNodes.innerHTML = html;
          dashboardNodes.classList.add("is-loaded");
          dashboardSearch?.dispatchEvent(new Event("input"));
        } catch (_) {
          if (!showErrorState) {
            return;
          }
          dashboardNodes.innerHTML = `
            <div class="card border-0 shadow-sm">
              <div class="card-body py-5 text-center text-body-secondary">
                Failed to load nodes.
              </div>
            </div>
          `;
        }
      };

      loadDashboardNodes(true);
      window.setInterval(() => {
        loadDashboardNodes(false);
      }, 5000);
    }
  }

  dashboardSearch?.addEventListener("input", () => {
    const query = dashboardSearch.value.trim().toLowerCase();
    document.querySelectorAll(".dashboard-node-card").forEach((card) => {
      if (!(card instanceof HTMLElement)) {
        return;
      }
      const haystack = card.dataset.nodeSearch || "";
      const matches = query === "" || haystack.includes(query);
      card.classList.toggle("d-none", !matches);
    });
  });

  if (authToggle instanceof HTMLElement) {
    const passwordRadio = document.getElementById("authModePassword");
    const keyRadio = document.getElementById("authModeKey");
    const passwordPanel = document.querySelector('[data-auth-panel="password"]');
    const keyPanel = document.querySelector('[data-auth-panel="key"]');
    const passwordInput = document.querySelector('[data-auth-input="password"]');
    const keyInput = document.querySelector('[data-auth-input="key"]');

    const syncAuthMode = () => {
      const passwordMode = passwordRadio instanceof HTMLInputElement && passwordRadio.checked;

      passwordPanel?.classList.toggle("d-none", !passwordMode);
      keyPanel?.classList.toggle("d-none", passwordMode);

      if (passwordInput instanceof HTMLInputElement) {
        passwordInput.disabled = !passwordMode;
        passwordInput.required = passwordMode;
        if (!passwordMode) {
          passwordInput.value = "";
        }
      }

      if (keyInput instanceof HTMLInputElement) {
        keyInput.disabled = passwordMode;
        keyInput.required = !passwordMode;
        if (passwordMode) {
          keyInput.value = "";
        }
      }
    };

    passwordRadio?.addEventListener("change", syncAuthMode);
    keyRadio?.addEventListener("change", syncAuthMode);
    syncAuthMode();
  }

  if (themeModeInput instanceof HTMLInputElement) {
    themeRadios.forEach((radio) => {
      radio.addEventListener("change", () => {
        if (radio instanceof HTMLInputElement && radio.checked) {
          themeModeInput.value = radio.value;
        }
      });
    });
  }

  if (uptimeChart instanceof HTMLCanvasElement && typeof Chart !== "undefined") {
    try {
      const labels = JSON.parse(uptimeChart.dataset.labels || "[]");
      const values = JSON.parse(uptimeChart.dataset.values || "[]");
      const pointColors = JSON.parse(uptimeChart.dataset.pointColors || "[]");
      const style = getComputedStyle(document.body);
      const primaryRGB = style.getPropertyValue("--color-primary-500").trim() || "16 185 129";
      const chartStroke = `rgb(${primaryRGB})`;
      const chartFill = `rgba(${primaryRGB.replace(/\s+/g, ", ")}, 0.16)`;
      const gridColor = style.getPropertyValue("--ma-border").trim() || "rgba(148, 163, 184, 0.16)";
      const tickColor = style.getPropertyValue("--bs-secondary-color").trim() || "#94a3b8";

      new Chart(uptimeChart, {
        type: "line",
        data: {
          labels,
          datasets: [{
            data: values,
            borderColor: chartStroke,
            backgroundColor: chartFill,
            fill: true,
            borderWidth: 3,
            tension: 0.35,
            pointRadius: 3,
            pointHoverRadius: 4,
            pointBackgroundColor: pointColors,
            pointBorderColor: pointColors,
            pointBorderWidth: 0,
          }],
        },
        options: {
          responsive: true,
          maintainAspectRatio: false,
          animation: false,
          plugins: {
            legend: {
              display: false,
            },
            tooltip: {
              displayColors: false,
              callbacks: {
                label(context) {
                  return `${Number(context.parsed.y || 0).toFixed(0)}% availability`;
                },
              },
            },
          },
          interaction: {
            intersect: false,
            mode: "index",
          },
          scales: {
            x: {
              grid: {
                display: false,
              },
              border: {
                display: false,
              },
              ticks: {
                color: tickColor,
                maxRotation: 0,
                autoSkip: true,
                maxTicksLimit: 6,
              },
            },
            y: {
              min: 0,
              max: 100,
              border: {
                display: false,
              },
              ticks: {
                color: tickColor,
                stepSize: 25,
                callback(value) {
                  return `${value}%`;
                },
              },
              grid: {
                color: gridColor,
                drawTicks: false,
              },
            },
          },
        },
      });
    } catch (_) {
      // Ignore malformed chart payloads.
    }
  }

  document.addEventListener("click", async (event) => {
    const target = event.target;
    if (!(target instanceof Element)) {
      return;
    }

    const copyTrigger = target.closest("[data-copy-value]");
    if (!(copyTrigger instanceof HTMLElement)) {
      return;
    }

    const value = (copyTrigger.dataset.copyValue || "").trim();
    if (!value) {
      return;
    }

    try {
      await navigator.clipboard.writeText(value);
    } catch (_) {
      return;
    }

    if (typeof bootstrap !== "undefined") {
      const tooltip = bootstrap.Tooltip.getOrCreateInstance(copyTrigger);
      const previousTitle = copyTrigger.getAttribute("data-bs-title") || copyTrigger.getAttribute("title") || "Copy";
      copyTrigger.setAttribute("data-bs-title", "Copied");
      tooltip.setContent?.({ ".tooltip-inner": "Copied" });
      tooltip.show();
      window.setTimeout(() => {
        copyTrigger.setAttribute("data-bs-title", previousTitle);
        tooltip.setContent?.({ ".tooltip-inner": previousTitle });
      }, 1200);
    }
  });

  if (typeof bootstrap !== "undefined") {
    document.querySelectorAll('[data-bs-toggle-tooltip="tooltip"]').forEach((element) => {
      new bootstrap.Tooltip(element);
    });
  }
});
