import { useEffect, useMemo, useRef, useState } from 'react';
import { useClient } from 'hooks/useClient';
import { fmtBytes, fmtDuration } from './shared';
import { LogStream } from './LogStream';

type Proc = { id: number; name: string; status: string; pid: number | null; cpuPct: number; memBytes: number; restarts: number; uptimeMs: number };
type SortKey = 'id' | 'name' | 'status' | 'cpuPct' | 'memBytes' | 'restarts' | 'uptimeMs' | 'pid';

const POLL_MS = 2000;
const statusColor = (s: string) =>
  s === 'online' ? 'bg-emerald-500' : s === 'stopped' ? 'bg-muted-foreground/40' : s === 'errored' ? 'bg-red-500' : 'bg-amber-500';

const COLS: { key: SortKey; label: string; align: 'left' | 'right' }[] = [
  { key: 'id', label: '#', align: 'right' },
  { key: 'name', label: 'Name', align: 'left' },
  { key: 'status', label: 'Status', align: 'left' },
  { key: 'cpuPct', label: 'CPU%', align: 'right' },
  { key: 'memBytes', label: 'Mem', align: 'right' },
  { key: 'restarts', label: '↺', align: 'right' },
  { key: 'uptimeMs', label: 'Uptime', align: 'left' },
  { key: 'pid', label: 'PID', align: 'right' },
];

export const Pm2View = () => {
  const { get } = useClient();
  const [procs, setProcs] = useState<Proc[] | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [sortKey, setSortKey] = useState<SortKey>('cpuPct');
  const [sortDir, setSortDir] = useState<'asc' | 'desc'>('desc');
  const [selected, setSelected] = useState<{ id: number; name: string } | null>(null);
  const alive = useRef(true);

  useEffect(() => {
    alive.current = true;
    const tick = () =>
      get<{ processes: Proc[]; error?: string }>('/system-monitor/pm2')
        .then((r) => {
          if (alive.current) {
            setProcs(r.processes);
            setError(r.error ?? null);
          }
        })
        .catch(() => alive.current && setError('Failed to read pm2'));
    tick();
    const id = setInterval(tick, POLL_MS);
    return () => {
      alive.current = false;
      clearInterval(id);
    };
  }, []);

  const toggleSort = (key: SortKey) => {
    if (key === sortKey) setSortDir((d) => (d === 'asc' ? 'desc' : 'asc'));
    else {
      setSortKey(key);
      setSortDir(key === 'name' || key === 'status' ? 'asc' : 'desc'); // text asc, numeric desc by default
    }
  };

  const sorted = useMemo(() => {
    const arr = [...(procs ?? [])];
    arr.sort((a, b) => {
      const av = a[sortKey] ?? 0;
      const bv = b[sortKey] ?? 0;
      const cmp = typeof av === 'string' && typeof bv === 'string' ? av.localeCompare(bv) : (av as number) - (bv as number);
      return sortDir === 'asc' ? cmp : -cmp;
    });
    return arr;
  }, [procs, sortKey, sortDir]);

  if (selected)
    return (
      <LogStream
        streamUrl={`/api/system-monitor/pm2/logs?id=${selected.id}&lines=150`}
        title={selected.name}
        backLabel="pm2"
        onBack={() => setSelected(null)}
      />
    );

  return (
    <div className="h-full w-full overflow-y-auto p-4 md:p-6">
      <div className="mx-auto max-w-5xl">
        <div className="mb-3 text-xs text-muted-foreground">pm2 · {procs?.length ?? 0} processes · click a name for live logs</div>
        {error && <div className="mb-3 rounded-lg border border-red-500/40 bg-red-500/10 p-3 text-sm text-red-500">{error}</div>}
        <div className="overflow-x-auto rounded-xl border border-border bg-card">
          <table className="w-full text-left text-sm">
            <thead>
              <tr className="text-xs uppercase tracking-wide text-muted-foreground">
                {COLS.map((c) => (
                  <th key={c.key} className={`p-3 font-medium ${c.align === 'right' ? 'text-right' : ''}`}>
                    <button
                      type="button"
                      onClick={() => toggleSort(c.key)}
                      className={`inline-flex items-center gap-1 hover:text-foreground ${c.align === 'right' ? 'flex-row-reverse' : ''} ${sortKey === c.key ? 'text-foreground' : ''}`}
                    >
                      {c.label}
                      <span className="w-2 text-[10px]">{sortKey === c.key ? (sortDir === 'asc' ? '▲' : '▼') : ''}</span>
                    </button>
                  </th>
                ))}
              </tr>
            </thead>
            <tbody>
              {sorted.map((p) => (
                <tr key={p.id} className="border-t border-border/60">
                  <td className="p-3 text-right font-mono text-muted-foreground">{p.id}</td>
                  <td className="p-3">
                    <button
                      type="button"
                      onClick={() => setSelected({ id: p.id, name: p.name })}
                      className="font-medium text-foreground hover:text-primary hover:underline"
                    >
                      {p.name}
                    </button>
                  </td>
                  <td className="p-3">
                    <span className="inline-flex items-center gap-1.5 text-xs text-muted-foreground">
                      <span className={`inline-block h-2 w-2 rounded-full ${statusColor(p.status)}`} />
                      {p.status}
                    </span>
                  </td>
                  <td className="p-3 text-right font-mono text-foreground">{p.cpuPct.toFixed(0)}</td>
                  <td className="p-3 text-right font-mono text-muted-foreground">{fmtBytes(p.memBytes)}</td>
                  <td className="p-3 text-right font-mono text-muted-foreground">{p.restarts}</td>
                  <td className="p-3 text-muted-foreground">{fmtDuration(p.uptimeMs)}</td>
                  <td className="p-3 text-right font-mono text-muted-foreground">{p.pid ?? '—'}</td>
                </tr>
              ))}
              {procs && procs.length === 0 && (
                <tr>
                  <td colSpan={8} className="p-3 text-muted-foreground">no processes</td>
                </tr>
              )}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  );
};
