"use client";
import { useRouter } from "next/navigation";
import { useEffect, useState } from "react";

type Host = {
  id: string;
  name: string;
  host: string;
  port: number;
  username: string;
  authType: string;
  hasAuth: boolean;
  notes: string | null;
  agents: number;
  lastSeenAt: string | null;
};

type ScanCandidate = {
  name: string;
  kind: string;
  deployMethod: string;
  deployRef: string;
  evidence: string;
  alreadyImported?: boolean;
};

type ScanState = {
  hostId: string;
  hostName: string;
  loading: boolean;
  candidates: ScanCandidate[];
  selected: Set<number>;
  errors: string[];
  message?: string;
};

type MetricsSummary = {
  loading?: boolean;
  error?: string;
  cpuPct?: number;
  cpuCount?: number;
  memPct?: number;
  memUsed?: number;
  memTotal?: number;
  diskPct?: number;
  diskUsed?: number;
  diskTotal?: number;
  diskMount?: string;
  load1?: number;
  uptimeSec?: number;
  ranAt?: string;
};

export default function HostsClient({ initial }: { initial: Host[] }) {
  const router = useRouter();
  const [hosts, setHosts] = useState(initial);
  const [showForm, setShowForm] = useState(initial.length === 0);
  const [editingId, setEditingId] = useState<string | null>(null);
  const [busy, setBusy] = useState<string>("");
  const [testResult, setTestResult] = useState<Record<string, string>>({});

  // form fields
  const [name, setName] = useState("");
  const [host, setHost] = useState("");
  const [port, setPort] = useState(22);
  const [username, setUsername] = useState("root");
  const [authType, setAuthType] = useState<"password" | "key">("password");
  const [password, setPassword] = useState("");
  const [privateKey, setPrivateKey] = useState("");
  const [notes, setNotes] = useState("");

  function resetForm() {
    setName(""); setHost(""); setPort(22); setUsername("root");
    setAuthType("password"); setPassword(""); setPrivateKey(""); setNotes("");
    setEditingId(null);
  }

  function startEdit(h: Host) {
    setEditingId(h.id);
    setName(h.name); setHost(h.host); setPort(h.port); setUsername(h.username);
    setAuthType(h.authType as "password" | "key"); setPassword(""); setPrivateKey("");
    setNotes(h.notes || "");
    setShowForm(true);
  }

  async function submit(e: React.FormEvent) {
    e.preventDefault();
    setBusy("save");
    const body: Record<string, unknown> = { name, host, port, username, authType, notes };
    if (password) body.password = password;
    if (privateKey) body.privateKey = privateKey;
    const r = editingId
      ? await fetch(`/api/hosts/${editingId}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) })
      : await fetch("/api/hosts", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) });
    setBusy("");
    if (!r.ok) { alert("Lưu thất bại"); return; }
    resetForm();
    setShowForm(false);
    router.refresh();
    setTimeout(() => location.reload(), 100);
  }

  async function remove(id: string) {
    if (!confirm("Xoá host này?")) return;
    const r = await fetch(`/api/hosts/${id}`, { method: "DELETE" });
    if (!r.ok) { alert("Xoá thất bại (host đang có agent?)"); return; }
    setHosts(hosts.filter((h) => h.id !== id));
  }

  async function testConn(id: string) {
    setBusy(`test:${id}`);
    setTestResult({ ...testResult, [id]: "đang kiểm tra..." });
    const r = await fetch(`/api/hosts/${id}/test`, { method: "POST" });
    const j = await r.json().catch(() => ({}));
    setBusy("");
    setTestResult({
      ...testResult,
      [id]: j.ok
        ? `✓ ${(j.stdout || "").split("\n")[0]?.slice(0, 80)}`
        : `✗ ${j.stderr || j.error || "lỗi"}`,
    });
  }

  // ---------- metrics inline ----------
  const [metricsMap, setMetricsMap] = useState<Record<string, MetricsSummary>>({});

  async function loadMetrics(hostId: string) {
    setMetricsMap((m) => ({ ...m, [hostId]: { ...(m[hostId] || {}), loading: true, error: undefined } }));
    try {
      const r = await fetch(`/api/hosts/${hostId}/metrics`);
      const j = await r.json();
      if (!r.ok) {
        setMetricsMap((m) => ({ ...m, [hostId]: { loading: false, error: j.error || "probe_failed" } }));
        return;
      }
      const d = j.metrics;
      const root = d.disk.find((x: { mount: string }) => x.mount === "/") || d.disk[0];
      setMetricsMap((m) => ({
        ...m,
        [hostId]: {
          loading: false,
          cpuPct: d.cpu.percent,
          cpuCount: d.cpu.count,
          memPct: d.mem.percent,
          memUsed: d.mem.used,
          memTotal: d.mem.total,
          diskPct: root?.percent,
          diskUsed: root?.used,
          diskTotal: root?.total,
          diskMount: root?.mount,
          load1: d.load.load1,
          uptimeSec: d.load.uptimeSec,
          ranAt: j.ranAt,
        },
      }));
    } catch (e) {
      setMetricsMap((m) => ({ ...m, [hostId]: { loading: false, error: (e as Error).message } }));
    }
  }

  async function loadAllMetrics() {
    await Promise.all(hosts.map((h) => loadMetrics(h.id)));
  }

  // Auto-load lần đầu + auto-refresh mỗi 30s
  useEffect(() => {
    loadAllMetrics();
    const t = setInterval(loadAllMetrics, 30_000);
    return () => clearInterval(t);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [hosts.length]);

  // ---------- scan agents trên host ----------
  const [scan, setScan] = useState<ScanState | null>(null);

  async function startScan(h: Host) {
    setScan({ hostId: h.id, hostName: h.name, loading: true, candidates: [], selected: new Set(), errors: [] });
    const r = await fetch(`/api/hosts/${h.id}/scan`, { method: "POST" });
    const j = await r.json().catch(() => ({}));
    if (!r.ok) {
      setScan((prev) => prev ? { ...prev, loading: false, errors: [j.error || "scan_failed"] } : null);
      return;
    }
    const cands: ScanCandidate[] = j.candidates || [];
    const sel = new Set<number>();
    cands.forEach((c, i) => { if (!c.alreadyImported) sel.add(i); });
    setScan((prev) => prev ? {
      ...prev,
      loading: false,
      candidates: cands,
      selected: sel,
      errors: j.errors || [],
    } : null);
  }

  function toggleSel(i: number) {
    setScan((prev) => {
      if (!prev) return null;
      const sel = new Set(prev.selected);
      if (sel.has(i)) sel.delete(i); else sel.add(i);
      return { ...prev, selected: sel };
    });
  }

  async function importSelected() {
    if (!scan) return;
    const items = Array.from(scan.selected).map((i) => scan.candidates[i]);
    if (items.length === 0) { setScan({ ...scan, message: "Chưa chọn agent nào." }); return; }
    setScan({ ...scan, loading: true, message: "Đang import..." });
    const r = await fetch(`/api/hosts/${scan.hostId}/import`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ items }),
    });
    const j = await r.json().catch(() => ({}));
    setScan({ ...scan, loading: false, message: r.ok
      ? `✓ Đã import ${j.created?.length || 0} agent${j.skipped?.length ? `, bỏ qua ${j.skipped.length}` : ""}.`
      : `✗ Lỗi: ${j.error || "unknown"}`,
    });
    if (r.ok) {
      setTimeout(() => {
        setScan(null);
        location.reload();
      }, 1500);
    }
  }

  return (
    <div className="space-y-5">
      <header className="flex items-end justify-between flex-wrap gap-3">
        <div>
          <div className="text-[11px] uppercase tracking-[0.18em] text-muted mb-1">Hạ tầng</div>
          <h1 className="text-2xl font-semibold tracking-tight">Hosts</h1>
          <div className="text-sm text-muted mt-1">{hosts.length} host · CPU/RAM/Disk realtime qua SSH</div>
        </div>
        <div className="flex gap-2">
          <button className="btn" onClick={loadAllMetrics} title="Đo lại CPU/RAM/Disk tất cả host">
            ↻ Tải lại metrics
          </button>
          <button className="btn btn-primary" onClick={() => { resetForm(); setShowForm(!showForm); }}>
            {showForm && !editingId ? "Đóng form" : "+ Thêm host"}
          </button>
        </div>
      </header>

      {showForm && (
        <form className="card p-5 space-y-3 max-w-xl" onSubmit={submit}>
          <h2 className="font-medium">{editingId ? "Sửa host" : "Thêm host"}</h2>
          <div className="grid grid-cols-2 gap-3">
            <div>
              <label className="label">Tên</label>
              <input className="input" value={name} onChange={(e) => setName(e.target.value)} required placeholder="lxc-4017" />
            </div>
            <div>
              <label className="label">Địa chỉ</label>
              <input className="input font-mono" value={host} onChange={(e) => setHost(e.target.value)} required placeholder="192.168.40.27" />
            </div>
            <div>
              <label className="label">Port</label>
              <input type="number" className="input" value={port} onChange={(e) => setPort(parseInt(e.target.value) || 22)} />
            </div>
            <div>
              <label className="label">User</label>
              <input className="input" value={username} onChange={(e) => setUsername(e.target.value)} />
            </div>
          </div>
          <div>
            <label className="label">Phương thức xác thực</label>
            <select className="input" value={authType} onChange={(e) => setAuthType(e.target.value as "password" | "key")}>
              <option value="password">Mật khẩu</option>
              <option value="key">SSH key</option>
            </select>
          </div>
          {authType === "password" ? (
            <div>
              <label className="label">Mật khẩu {editingId && "(để trống = giữ nguyên)"}</label>
              <input type="password" className="input" value={password} onChange={(e) => setPassword(e.target.value)} />
            </div>
          ) : (
            <div>
              <label className="label">Private key {editingId && "(để trống = giữ nguyên)"}</label>
              <textarea className="input font-mono min-h-[120px]" value={privateKey} onChange={(e) => setPrivateKey(e.target.value)} placeholder="-----BEGIN OPENSSH PRIVATE KEY-----" />
            </div>
          )}
          <div>
            <label className="label">Ghi chú</label>
            <input className="input" value={notes} onChange={(e) => setNotes(e.target.value)} />
          </div>
          <div className="flex gap-2">
            <button className="btn btn-primary" type="submit" disabled={busy === "save"}>
              {busy === "save" ? "Đang lưu..." : (editingId ? "Cập nhật" : "Thêm")}
            </button>
            <button type="button" className="btn" onClick={() => { resetForm(); setShowForm(false); }}>Huỷ</button>
          </div>
        </form>
      )}

      {hosts.length === 0 ? (
        <div className="card p-10 text-center text-muted">Chưa có host nào.</div>
      ) : (
        <div className="card overflow-x-auto">
          <table className="table w-full text-sm">
            <thead>
              <tr>
                <th>Tên</th>
                <th>Địa chỉ</th>
                <th>Auth</th>
                <th>Agents</th>
                <th className="w-[110px]">CPU</th>
                <th className="w-[110px]">RAM</th>
                <th className="w-[110px]">Disk</th>
                <th>Uptime</th>
                <th>Last seen</th>
                <th></th>
              </tr>
            </thead>
            <tbody>
              {hosts.map((h) => {
                const m = metricsMap[h.id];
                return (
                  <tr key={h.id}>
                    <td className="font-medium">{h.name}</td>
                    <td className="font-mono text-xs">{h.host}:{h.port}<div className="text-muted">{h.username}</div></td>
                    <td><span className="chip">{h.authType} {h.hasAuth ? "✓" : "✗"}</span></td>
                    <td>{h.agents}</td>
                    <td><MetricBar kind="cpu" m={m} onReload={() => loadMetrics(h.id)} /></td>
                    <td><MetricBar kind="ram" m={m} onReload={() => loadMetrics(h.id)} /></td>
                    <td><MetricBar kind="disk" m={m} onReload={() => loadMetrics(h.id)} /></td>
                    <td className="text-xs font-mono">{m?.uptimeSec != null ? fmtUptime(m.uptimeSec) : "-"}</td>
                    <td className="text-xs text-muted">
                      {h.lastSeenAt ? new Date(h.lastSeenAt).toLocaleString("vi-VN") : "-"}
                      {testResult[h.id] && <div className="text-[11px] mt-0.5">{testResult[h.id]}</div>}
                    </td>
                    <td className="text-right">
                      <div className="flex gap-1 justify-end flex-wrap">
                        <button className="btn" onClick={() => testConn(h.id)} disabled={busy === `test:${h.id}`}>
                          {busy === `test:${h.id}` ? "..." : "Test"}
                        </button>
                        <button className="btn" onClick={() => startScan(h)}>Quét agent</button>
                        <button className="btn" onClick={() => startEdit(h)}>Sửa</button>
                        <button className="btn btn-danger" onClick={() => remove(h.id)}>Xoá</button>
                      </div>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      )}

      {scan && (
        <div className="fixed inset-0 z-50 bg-black/60 flex items-start justify-center p-4 overflow-y-auto" onClick={(e) => { if (e.target === e.currentTarget) setScan(null); }}>
          <div className="card max-w-3xl w-full p-5 my-8 space-y-3">
            <div className="flex items-center justify-between">
              <h2 className="font-medium">Quét agent trên <span className="font-mono">{scan.hostName}</span></h2>
              <button className="btn" onClick={() => setScan(null)}>Đóng</button>
            </div>
            {scan.loading && <div className="text-muted text-sm">Đang quét systemd / docker / pm2...</div>}
            {!scan.loading && scan.candidates.length === 0 && (
              <div className="text-muted text-sm">Không tìm thấy agent nào trên host này.</div>
            )}
            {scan.errors.length > 0 && (
              <div className="text-warn text-xs space-y-1">
                {scan.errors.map((e, i) => <div key={i}>⚠ {e}</div>)}
              </div>
            )}
            {scan.candidates.length > 0 && (
              <>
                <div className="text-xs text-muted">
                  Tick chọn các agent muốn import vào AM (chế độ &quot;khai báo&quot;). Mặc định bỏ tick những cái đã có.
                </div>
                <div className="border border-border rounded divide-y divide-border max-h-[55vh] overflow-y-auto">
                  {scan.candidates.map((c, i) => (
                    <label key={i} className={`flex items-start gap-3 p-3 cursor-pointer hover:bg-panel2 ${c.alreadyImported ? "opacity-60" : ""}`}>
                      <input
                        type="checkbox"
                        className="mt-1"
                        checked={scan.selected.has(i)}
                        onChange={() => toggleSel(i)}
                        disabled={c.alreadyImported}
                      />
                      <div className="flex-1 min-w-0">
                        <div className="flex items-center gap-2 flex-wrap">
                          <span className="font-medium">{c.name}</span>
                          <span className="chip">{c.kind}</span>
                          <span className="chip">{c.deployMethod}</span>
                          {c.alreadyImported && <span className="chip text-muted">đã import</span>}
                        </div>
                        <div className="text-xs text-muted font-mono mt-1">{c.deployRef}</div>
                        <div className="text-xs text-muted mt-0.5">{c.evidence}</div>
                      </div>
                    </label>
                  ))}
                </div>
                <div className="flex items-center gap-2">
                  <button className="btn btn-primary" onClick={importSelected} disabled={scan.loading}>
                    {scan.loading ? "Đang import..." : `Import ${scan.selected.size} agent`}
                  </button>
                  <button className="btn" onClick={() => setScan({ ...scan, selected: new Set(scan.candidates.map((_, i) => i).filter((i) => !scan.candidates[i].alreadyImported)) })}>Chọn tất cả</button>
                  <button className="btn" onClick={() => setScan({ ...scan, selected: new Set() })}>Bỏ chọn</button>
                  {scan.message && <div className="text-xs text-muted ml-auto">{scan.message}</div>}
                </div>
              </>
            )}
          </div>
        </div>
      )}
    </div>
  );
}

function MetricBar({ kind, m, onReload }: { kind: "cpu" | "ram" | "disk"; m?: MetricsSummary; onReload: () => void }) {
  if (!m) return <span className="text-xs text-muted">...</span>;
  if (m.error && m.cpuPct === undefined) {
    return <span className="text-xs text-bad cursor-pointer" title={m.error} onClick={onReload}>✗</span>;
  }

  let pct = 0;
  let sub = "";
  if (kind === "cpu") {
    pct = m.cpuPct ?? 0;
    sub = `${m.cpuCount ?? "-"}c · ${(m.load1 ?? 0).toFixed(1)}`;
  } else if (kind === "ram") {
    pct = m.memPct ?? 0;
    sub = `${fmtBytesShort(m.memUsed ?? 0)}/${fmtBytesShort(m.memTotal ?? 0)}`;
  } else {
    pct = m.diskPct ?? 0;
    sub = `${fmtBytesShort(m.diskUsed ?? 0)}/${fmtBytesShort(m.diskTotal ?? 0)}`;
  }

  if (m.loading && pct === 0 && !sub) {
    return <span className="text-xs text-muted">đo...</span>;
  }

  const p = Math.max(0, Math.min(100, pct));
  const color = p >= 90 ? "bg-bad" : p >= 70 ? "bg-warn" : "bg-accent";
  return (
    <div
      className="cursor-pointer"
      title={`${pct.toFixed(1)}% · click để refresh${m.ranAt ? ` · ${new Date(m.ranAt).toLocaleTimeString("vi-VN")}` : ""}`}
      onClick={onReload}
    >
      <div className="flex items-center gap-1.5 text-[11px]">
        <div className="flex-1 h-1.5 bg-bg rounded overflow-hidden">
          <div className={`h-full ${color} transition-all`} style={{ width: `${p}%` }} />
        </div>
        <span className="font-mono w-9 text-right">{Math.round(p)}%</span>
      </div>
      <div className="text-[10px] text-muted font-mono mt-0.5 truncate">{sub}</div>
    </div>
  );
}

function fmtBytesShort(n: number): string {
  if (!n || n < 0) return "-";
  const u = ["B", "K", "M", "G", "T"];
  let i = 0; let v = n;
  while (v >= 1024 && i < u.length - 1) { v /= 1024; i++; }
  return `${v.toFixed(v < 10 && i > 0 ? 1 : 0)}${u[i]}`;
}

function ResourceCell({ metrics, onReload }: { metrics?: MetricsSummary; onReload: () => void }) {
  if (!metrics) {
    return (
      <button className="text-xs text-muted hover:text-accent" onClick={onReload}>
        Đang tải...
      </button>
    );
  }
  if (metrics.error) {
    return (
      <div className="text-xs">
        <span className="text-bad">✗ {metrics.error}</span>
        <button className="ml-2 text-accent hover:underline" onClick={onReload}>thử lại</button>
      </div>
    );
  }
  if (metrics.loading && metrics.cpuPct === undefined) {
    return <div className="text-xs text-muted">Đang đo...</div>;
  }
  return (
    <div
      className="space-y-1 min-w-[260px] cursor-pointer"
      title={`Đo lúc: ${metrics.ranAt ? new Date(metrics.ranAt).toLocaleString("vi-VN") : "-"} · click để refresh`}
      onClick={onReload}
    >
      <MiniBar label="CPU" pct={metrics.cpuPct ?? 0} sub={`${metrics.cpuCount ?? "-"}c · load ${(metrics.load1 ?? 0).toFixed(2)}`} />
      <MiniBar label="RAM" pct={metrics.memPct ?? 0} sub={`${fmtBytes(metrics.memUsed ?? 0)} / ${fmtBytes(metrics.memTotal ?? 0)}`} />
      <MiniBar
        label={metrics.diskMount && metrics.diskMount !== "/" ? `Disk${metrics.diskMount}` : "Disk"}
        pct={metrics.diskPct ?? 0}
        sub={`${fmtBytes(metrics.diskUsed ?? 0)} / ${fmtBytes(metrics.diskTotal ?? 0)} · up ${fmtUptime(metrics.uptimeSec ?? 0)}`}
      />
      {metrics.loading && <div className="text-[10px] text-muted">đang refresh...</div>}
    </div>
  );
}

function MiniBar({ label, pct, sub }: { label: string; pct: number; sub: string }) {
  const p = Math.max(0, Math.min(100, pct));
  const color = p >= 90 ? "bg-bad" : p >= 70 ? "bg-warn" : "bg-accent";
  return (
    <div className="text-[11px]">
      <div className="flex items-center justify-between gap-2">
        <span className="text-muted w-9 shrink-0">{label}</span>
        <div className="flex-1 h-1 bg-bg rounded overflow-hidden">
          <div className={`h-full ${color}`} style={{ width: `${p}%` }} />
        </div>
        <span className="font-mono w-10 text-right">{p}%</span>
      </div>
      <div className="text-[10px] text-muted ml-11">{sub}</div>
    </div>
  );
}

function fmtBytes(n: number): string {
  if (!n || n < 0) return "-";
  const u = ["B", "KB", "MB", "GB", "TB"];
  let i = 0; let v = n;
  while (v >= 1024 && i < u.length - 1) { v /= 1024; i++; }
  return `${v.toFixed(v < 10 && i > 0 ? 1 : 0)} ${u[i]}`;
}

function fmtUptime(sec: number): string {
  if (!sec || sec < 0) return "-";
  const d = Math.floor(sec / 86400);
  const h = Math.floor((sec % 86400) / 3600);
  const m = Math.floor((sec % 3600) / 60);
  if (d > 0) return `${d}d ${h}h`;
  if (h > 0) return `${h}h ${m}m`;
  return `${m}m`;
}
