<script>
  import { onDestroy } from "svelte";

  const hosts = [
    { id: "nas", label: "NAS" },
    { id: "vps", label: "VPS" },
  ];

  let mobileHost = $state("nas");
  let terminals = $state({});
  let cleanups = [];

  function initTerminal(el, hostId) {
    (async () => {
      const { Terminal } = await import("@xterm/xterm");
      const { FitAddon } = await import("@xterm/addon-fit");
      await import("@xterm/xterm/css/xterm.css");

      const term = new Terminal({
        cursorBlink: true,
        fontSize: 13,
        fontFamily: "'JetBrains Mono', 'Fira Code', 'SF Mono', 'Menlo', monospace",
        lineHeight: 1.4,
        theme: {
          background: "#0f172a",
          foreground: "#e2e8f0",
          cursor: "#6366f1",
          cursorAccent: "#0f172a",
          selectionBackground: "#334155",
          black: "#0f172a",
          red: "#f43f5e",
          green: "#10b981",
          yellow: "#f59e0b",
          blue: "#3b82f6",
          magenta: "#a855f7",
          cyan: "#06b6d4",
          white: "#e2e8f0",
        },
      });
      const fit = new FitAddon();
      term.loadAddon(fit);
      term.open(el);
      fit.fit();

      const proto = location.protocol === "https:" ? "wss:" : "ws:";
      const token = localStorage.getItem("token") || "";
      const ws = new WebSocket(
        `${proto}//${location.host}/ws/terminal?token=${encodeURIComponent(token)}&host=${hostId}`
      );
      ws.binaryType = "arraybuffer";

      function sendSize() {
        if (ws.readyState === 1) {
          const buf = new Uint8Array(5);
          buf[0] = 0x01;
          new DataView(buf.buffer).setUint16(1, term.cols);
          new DataView(buf.buffer).setUint16(3, term.rows);
          ws.send(buf);
        }
      }

      ws.onopen = () => {
        terminals[hostId] = { connected: true, error: "" };
        sendSize();
      };
      ws.onmessage = (e) => term.write(new Uint8Array(e.data));
      ws.onclose = () => {
        terminals[hostId] = { ...terminals[hostId], connected: false };
        term.write("\r\n\x1b[90m[Connection closed]\x1b[0m");
      };
      ws.onerror = () => {
        terminals[hostId] = { connected: false, error: "WebSocket connection failed" };
      };
      term.onData((data) => ws.readyState === 1 && ws.send(new TextEncoder().encode(data)));

      const ro = new ResizeObserver(() => {
        fit.fit();
        sendSize();
      });
      ro.observe(el);

      cleanups.push(() => {
        ro.disconnect();
        ws.close();
        term.dispose();
      });
    })();
  }

  onDestroy(() => cleanups.forEach((fn) => fn()));

  function statusFor(hostId) {
    const t = terminals[hostId];
    if (!t) return { connected: false, error: "" };
    return t;
  }
</script>

<div class="space-y-4">
  <div class="flex items-center justify-between">
    <div>
      <h1 class="text-2xl font-bold text-surface-900 tracking-tight">Terminal</h1>
      <div class="mt-2 md:hidden">
        <select
          class="bg-surface-800 text-surface-200 border border-surface-600 rounded-lg px-3 py-1.5 text-sm"
          bind:value={mobileHost}
        >
          {#each hosts as h}
            <option value={h.id}>{h.label}</option>
          {/each}
        </select>
      </div>
    </div>
  </div>

  <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
    {#each hosts as h (h.id)}
      <div class="hidden md:block" class:!block={mobileHost === h.id}>
        <div class="flex items-center gap-2 mb-2 text-sm text-surface-400">
          <span class="font-medium text-surface-200">{h.label}</span>
          {#if statusFor(h.id).connected}
            <span class="w-1.5 h-1.5 rounded-full bg-emerald-500"></span> Connected
          {:else if statusFor(h.id).error}
            <span class="text-rose-500">{statusFor(h.id).error}</span>
          {:else}
            <span class="w-1.5 h-1.5 rounded-full bg-amber-400 animate-pulse"></span> Connecting...
          {/if}
        </div>
        <div
          use:initTerminal={h.id}
          class="h-[calc(100vh-12rem)] rounded-xl overflow-hidden shadow-lg border border-surface-700"
          style="background: #0f172a;"
        ></div>
      </div>
    {/each}
  </div>
</div>
