import { useEffect, useRef, useState } from 'react';
import { useClient } from 'hooks/useClient';
import { Cpu, MemoryStick, HardDrive, Server, Thermometer, CircuitBoard, Network, Zap } from 'lucide-react';
import { fmtBytes, fmtDuration } from './shared';

type Sensor = { name: string; label: string; celsius: number };
type Stats = {
  hostname: string;
  platform: string;
  uptimeSec: number;
  loadavg: number[];
  cpu: { model: string; cores: number; usagePct: number; perCore: number[] };
  mem: { totalBytes: number; usedBytes: number; freeBytes: number; usedPct: number; swapTotalBytes: number; swapUsedBytes: number } | null;
  disks: { mount: string; fsType: string; totalBytes: number; usedBytes: number; usedPct: number }[];
  processes: { pid: number; user: string; cpuPct: number; memPct: number; command: string }[];
  temp: { cpuC: number | null; cpuLabel: string | null; sensors: Sensor[] } | null;
  gpu: { busyPct: number; vramUsedBytes: number; vramTotalBytes: number } | null;
  net: { rxBytesPerSec: number; txBytesPerSec: number; interfaces: { name: string; rxBytesPerSec: number; txBytesPerSec: number }[] } | null;
  power: { cpuWatts: number | null; gpuWatts: number | null } | null;
  timestamp: number;
};

const POLL_MS = 2000;

const barColor = (pct: number) => (pct >= 85 ? 'bg-red-500' : pct >= 60 ? 'bg-amber-500' : 'bg-emerald-500');
const tempColor = (c: number) => (c >= 80 ? 'text-red-500' : c >= 65 ? 'text-amber-500' : 'text-emerald-500');
const fmtRate = (bps: number) => `${fmtBytes(bps)}/s`;

const Bar = ({ pct }: { pct: number }) => (
  <div className="h-2 w-full overflow-hidden rounded-full bg-muted">
    <div className={`h-full rounded-full transition-all ${barColor(pct)}`} style={{ width: `${Math.min(100, pct)}%` }} />
  </div>
);

const Card = ({ title, icon: Icon, children, className }: { title: string; icon: typeof Cpu; children: React.ReactNode; className?: string }) => (
  <div className={`flex flex-col gap-3 rounded-xl border border-border bg-card p-4 ${className ?? ''}`}>
    <div className="flex items-center gap-2 text-sm font-medium text-muted-foreground">
      <Icon size={16} className="text-primary" />
      {title}
    </div>
    {children}
  </div>
);

export const BtopView = () => {
  const { get } = useClient();
  const [stats, setStats] = useState<Stats | null>(null);
  const [error, setError] = useState<string | null>(null);
  const alive = useRef(true);

  useEffect(() => {
    alive.current = true;
    const tick = () => {
      get<Stats>('/system-monitor/stats')
        .then((s) => {
          if (alive.current) {
            setStats(s);
            setError(null);
          }
        })
        .catch(() => alive.current && setError('Failed to read system stats'));
    };
    tick();
    const id = setInterval(tick, POLL_MS);
    return () => {
      alive.current = false;
      clearInterval(id);
    };
  }, []);

  return (
    <div className="h-full w-full overflow-y-auto p-4 md:p-6">
      <div className="mx-auto flex max-w-5xl flex-col gap-5">
        <div className="flex flex-wrap items-center justify-between gap-3 text-xs text-muted-foreground">
          <span>{stats ? `${stats.hostname} · ${stats.platform}` : 'Loading…'}</span>
          {stats && (
            <div className="flex items-center gap-4">
              <span>up {fmtDuration(stats.uptimeSec * 1000)}</span>
              <span>load {stats.loadavg.map((l) => l.toFixed(2)).join('  ')}</span>
              <span className="inline-flex h-2 w-2 animate-pulse rounded-full bg-emerald-500" title="live" />
            </div>
          )}
        </div>

        {error && <div className="rounded-lg border border-red-500/40 bg-red-500/10 p-3 text-sm text-red-500">{error}</div>}

        {stats && (
          <>
            <div className="grid grid-cols-1 gap-4 @min-[600px]:grid-cols-2 @min-[960px]:grid-cols-3">
              <Card title="CPU" icon={Cpu}>
                <div className="flex items-end justify-between">
                  <span className="text-3xl font-semibold text-foreground">{stats.cpu.usagePct.toFixed(0)}%</span>
                  <span className="text-xs text-muted-foreground">{stats.cpu.cores} cores</span>
                </div>
                <Bar pct={stats.cpu.usagePct} />
                <p className="truncate text-xs text-muted-foreground" title={stats.cpu.model}>{stats.cpu.model}</p>
                <div className="grid grid-cols-8 gap-1 pt-1">
                  {stats.cpu.perCore.map((c, i) => (
                    <div key={i} className="flex h-10 items-end rounded bg-muted" title={`core ${i}: ${c}%`}>
                      <div className={`w-full rounded ${barColor(c)}`} style={{ height: `${Math.max(4, c)}%` }} />
                    </div>
                  ))}
                </div>
              </Card>

              <Card title="Memory" icon={MemoryStick}>
                {stats.mem ? (
                  <>
                    <div className="flex items-end justify-between">
                      <span className="text-3xl font-semibold text-foreground">{stats.mem.usedPct.toFixed(0)}%</span>
                      <span className="text-xs text-muted-foreground">
                        {fmtBytes(stats.mem.usedBytes)} / {fmtBytes(stats.mem.totalBytes)}
                      </span>
                    </div>
                    <Bar pct={stats.mem.usedPct} />
                    {stats.mem.swapTotalBytes > 0 && (
                      <p className="text-xs text-muted-foreground">
                        swap {fmtBytes(stats.mem.swapUsedBytes)} / {fmtBytes(stats.mem.swapTotalBytes)}
                      </p>
                    )}
                  </>
                ) : (
                  <p className="text-sm text-muted-foreground">unavailable</p>
                )}
              </Card>

              <Card title="Disks" icon={HardDrive}>
                {stats.disks.length ? (
                  <div className="flex flex-col gap-3">
                    {stats.disks.map((d) => (
                      <div key={d.mount} className="flex flex-col gap-1">
                        <div className="flex items-center justify-between text-xs">
                          <span className="truncate font-mono text-foreground" title={`${d.mount} (${d.fsType})`}>{d.mount}</span>
                          <span className="text-muted-foreground">{fmtBytes(d.usedBytes)} / {fmtBytes(d.totalBytes)}</span>
                        </div>
                        <Bar pct={d.usedPct} />
                      </div>
                    ))}
                  </div>
                ) : (
                  <p className="text-sm text-muted-foreground">no disks</p>
                )}
              </Card>

              <Card title="GPU" icon={CircuitBoard}>
                {stats.gpu ? (
                  <>
                    <div className="flex items-end justify-between">
                      <span className="text-3xl font-semibold text-foreground">{stats.gpu.busyPct}%</span>
                      <span className="text-xs text-muted-foreground">VRAM {fmtBytes(stats.gpu.vramUsedBytes)} / {fmtBytes(stats.gpu.vramTotalBytes)}</span>
                    </div>
                    <Bar pct={stats.gpu.busyPct} />
                    {stats.gpu.vramTotalBytes > 0 && <Bar pct={(stats.gpu.vramUsedBytes / stats.gpu.vramTotalBytes) * 100} />}
                  </>
                ) : (
                  <p className="text-sm text-muted-foreground">no gpu</p>
                )}
              </Card>

              <Card title="Temperature" icon={Thermometer}>
                {stats.temp?.cpuC != null ? (
                  <>
                    <div className="flex items-end justify-between">
                      <span className={`text-3xl font-semibold ${tempColor(stats.temp.cpuC)}`}>{stats.temp.cpuC.toFixed(0)}°C</span>
                      <span className="truncate pl-2 text-xs text-muted-foreground">{stats.temp.cpuLabel}</span>
                    </div>
                    <div className="flex flex-col gap-1 pt-1">
                      {stats.temp.sensors
                        .filter((s) => `${s.name} · ${s.label}` !== stats.temp!.cpuLabel)
                        .slice(0, 6)
                        .map((s, i) => (
                          <div key={i} className="flex items-center justify-between text-xs">
                            <span className="truncate text-muted-foreground">{s.name} · {s.label}</span>
                            <span className={`font-mono ${tempColor(s.celsius)}`}>{s.celsius.toFixed(0)}°C</span>
                          </div>
                        ))}
                    </div>
                  </>
                ) : (
                  <p className="text-sm text-muted-foreground">no sensors</p>
                )}
              </Card>

              <Card title="Network" icon={Network}>
                {stats.net ? (
                  <>
                    <div className="flex items-center justify-between text-lg font-semibold text-foreground">
                      <span>↓ {fmtRate(stats.net.rxBytesPerSec)}</span>
                      <span>↑ {fmtRate(stats.net.txBytesPerSec)}</span>
                    </div>
                    <div className="flex flex-col gap-1 pt-1">
                      {stats.net.interfaces.slice(0, 4).map((i) => (
                        <div key={i.name} className="flex items-center justify-between text-xs text-muted-foreground">
                          <span className="truncate font-mono">{i.name}</span>
                          <span className="font-mono">↓{fmtRate(i.rxBytesPerSec)} ↑{fmtRate(i.txBytesPerSec)}</span>
                        </div>
                      ))}
                      {stats.net.interfaces.length === 0 && <span className="text-xs text-muted-foreground">idle</span>}
                    </div>
                  </>
                ) : (
                  <p className="text-sm text-muted-foreground">unavailable</p>
                )}
              </Card>

              <Card title="Power" icon={Zap}>
                {stats.power ? (
                  <div className="flex flex-col gap-2 pt-1">
                    <div className="flex items-center justify-between text-sm">
                      <span className="text-muted-foreground">CPU package</span>
                      <span className="font-mono text-foreground">{stats.power.cpuWatts != null ? `${stats.power.cpuWatts} W` : '—'}</span>
                    </div>
                    <div className="flex items-center justify-between text-sm">
                      <span className="text-muted-foreground">GPU</span>
                      <span className="font-mono text-foreground">{stats.power.gpuWatts != null ? `${stats.power.gpuWatts} W` : '—'}</span>
                    </div>
                  </div>
                ) : (
                  <p className="text-sm text-muted-foreground">unavailable</p>
                )}
              </Card>
            </div>

            <Card title="Top processes" icon={Server}>
              <div className="overflow-x-auto">
                <table className="w-full text-left text-sm">
                  <thead>
                    <tr className="text-xs uppercase tracking-wide text-muted-foreground">
                      <th className="pb-2 pr-4 font-medium">PID</th>
                      <th className="pb-2 pr-4 font-medium">User</th>
                      <th className="pb-2 pr-4 text-right font-medium">CPU%</th>
                      <th className="pb-2 pr-4 text-right font-medium">MEM%</th>
                      <th className="pb-2 font-medium">Command</th>
                    </tr>
                  </thead>
                  <tbody>
                    {stats.processes.map((p) => (
                      <tr key={p.pid} className="border-t border-border/60">
                        <td className="py-1.5 pr-4 font-mono text-muted-foreground">{p.pid}</td>
                        <td className="py-1.5 pr-4 text-muted-foreground">{p.user}</td>
                        <td className="py-1.5 pr-4 text-right font-mono text-foreground">{p.cpuPct.toFixed(1)}</td>
                        <td className="py-1.5 pr-4 text-right font-mono text-muted-foreground">{p.memPct.toFixed(1)}</td>
                        <td className="max-w-0 truncate py-1.5 font-mono text-foreground" title={p.command}>{p.command}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            </Card>
          </>
        )}
      </div>
    </div>
  );
};
