const statusBadge = document.getElementById("status-badge");
const daemonDetails = document.getElementById("daemon-details");
const networkDetails = document.getElementById("network-details");
const logsOutput = document.getElementById("logs-output");
const actionMessage = document.getElementById("action-message");
const webUiLink = document.getElementById("web-ui-link");
const startBtn = document.getElementById("start-btn");
const stopBtn = document.getElementById("stop-btn");
const restartBtn = document.getElementById("restart-btn");
const refreshBtn = document.getElementById("refresh-btn");
const copyLogsBtn = document.getElementById("copy-logs-btn");
const autoRefreshLogs = document.getElementById("auto-refresh-logs");

let busy = false;
let logPath = "";

function setBusy(next) {
  busy = next;
  startBtn.disabled = next;
  stopBtn.disabled = next;
  restartBtn.disabled = next;
}

function setBadge(kind, label) {
  statusBadge.className = `badge badge-${kind}`;
  statusBadge.textContent = label;
}

function detailRow(label, value) {
  const wrap = document.createElement("div");
  const dt = document.createElement("dt");
  const dd = document.createElement("dd");
  dt.textContent = label;
  dd.textContent = value ?? "—";
  wrap.append(dt, dd);
  return wrap;
}

function renderDetails(container, rows) {
  container.replaceChildren();
  for (const row of rows) {
    container.append(detailRow(row[0], row[1]));
  }
}

async function fetchJson(url, options) {
  const response = await fetch(url, options);
  const body = await response.json();
  if (!response.ok) {
    throw new Error(body.error || `Request failed (${response.status})`);
  }
  return body;
}

function resolveOverallStatus(data) {
  const local = data.daemon?.localDaemon;
  const connected = data.daemon?.connectedDaemon;
  if (data.health.ok && connected === "reachable") {
    return { kind: "running", label: "Running" };
  }
  if (local === "running" || data.health.ok) {
    return { kind: "partial", label: "Degraded" };
  }
  if (local === "unresponsive") {
    return { kind: "partial", label: "Unresponsive" };
  }
  return { kind: "stopped", label: "Stopped" };
}

async function refreshStatus() {
  const data = await fetchJson("/api/status");
  const overall = resolveOverallStatus(data);
  setBadge(overall.kind, overall.label);

  const daemon = data.daemon;
  renderDetails(daemonDetails, [
    ["Server ID", daemon?.serverId],
    ["Local", daemon?.localDaemon],
    ["API", daemon?.connectedDaemon],
    ["PID", daemon?.pid != null ? String(daemon.pid) : null],
    ["Started", daemon?.startedAt],
    ["Version", daemon?.daemonVersion],
    ["Agents", formatAgents(daemon)],
    ["Home", daemon?.home],
    ["Logs", daemon?.logPath],
    ["Note", daemon?.note || data.error],
  ]);

  const listen = daemon?.listen || data.configListen || "0.0.0.0:6769";
  const port = listen.includes(":") ? listen.split(":").pop() : "6769";
  const tailscaleEndpoint =
    data.tailscale.ipv4 != null ? `${data.tailscale.ipv4}:${port}` : null;
  renderDetails(networkDetails, [
    ["Listen", daemon?.listen || data.configListen],
    ["Health", data.health.ok ? `OK (${data.health.statusCode})` : "Unreachable"],
    ["Health URL", data.health.url],
    ["Tailscale IP", data.tailscale.ipv4],
    ["Remote host", tailscaleEndpoint],
    ["Relay", daemon?.relay],
    ["Hostname", daemon?.hostname],
  ]);

  if (data.webUiUrl) {
    webUiLink.href = data.webUiUrl;
    webUiLink.classList.remove("hidden");
  } else {
    webUiLink.classList.add("hidden");
  }

  startBtn.disabled = busy || overall.kind === "running";
  stopBtn.disabled = busy || overall.kind === "stopped";
}

function formatAgents(daemon) {
  if (!daemon) return null;
  if (daemon.runningAgents == null || daemon.idleAgents == null) {
    return "Unavailable";
  }
  return `${daemon.runningAgents} running, ${daemon.idleAgents} idle`;
}

async function refreshLogs() {
  const data = await fetchJson("/api/logs?tail=250");
  logPath = data.logPath;
  logsOutput.textContent = data.contents || "(empty)";
  logsOutput.scrollTop = logsOutput.scrollHeight;
}

async function runAction(path) {
  setBusy(true);
  actionMessage.textContent = "Working…";
  try {
    const result = await fetchJson(path, { method: "POST" });
    actionMessage.textContent = result.message || "Done";
    await refreshStatus();
    await refreshLogs();
  } catch (error) {
    actionMessage.textContent = error instanceof Error ? error.message : String(error);
  } finally {
    setBusy(false);
    await refreshStatus();
  }
}

async function refreshAll() {
  try {
    await Promise.all([refreshStatus(), refreshLogs()]);
  } catch (error) {
    actionMessage.textContent = error instanceof Error ? error.message : String(error);
    setBadge("unknown", "Error");
  }
}

startBtn.addEventListener("click", () => void runAction("/api/daemon/start"));
stopBtn.addEventListener("click", () => void runAction("/api/daemon/stop"));
restartBtn.addEventListener("click", () => void runAction("/api/daemon/restart"));
refreshBtn.addEventListener("click", () => void refreshAll());

copyLogsBtn.addEventListener("click", async () => {
  if (!logPath) return;
  try {
    await navigator.clipboard.writeText(logPath);
    actionMessage.textContent = `Copied log path: ${logPath}`;
  } catch {
    actionMessage.textContent = logPath;
  }
});

setInterval(() => {
  if (autoRefreshLogs.checked) {
    void refreshLogs();
  }
}, 3000);

setInterval(() => {
  void refreshStatus();
}, 5000);

void refreshAll();
