/*
 * Cross-Forge Topology — a live render of the cross-forge status diagram:
 *   Linear (snapshot) → Hub → {local forge, teammate forges} → {memory, orchestration} planes
 *
 * The local forge + both planes poll live (no backend change needed). The Linear
 * lane reads the regen'd snapshot at GET /linear-crossref; the pool↔Linear
 * cross-reference is computed here against the live orchestration pool.
 * Mirrors TeamActivityPane's hub-gating + glassmorphism style.
 */
import {
  Network, Database, Boxes, Users, Zap, Layers,
  GitBranch, AlertTriangle, CheckCircle2, CircleDot,
} from 'lucide-react';
import {
  useGetXmemStatusQuery,
  useGetWorkspacesQuery,
  useGetXmemCurrentFocusQuery,
  useGetSharedTasksQuery,
  useGetLinearCrossrefQuery,
} from '../../store';
import { formatRelativeTime, getPriorityColor } from '../../lib/utils';

const POLL = 15000;
const SLOW_POLL = 60000;
const TERMINAL = new Set(['Done', 'Canceled', 'Cancelled', 'Duplicate']);
const SKA_RE = /SKA-\d+/;

function isStale(ts: string | null | undefined, hours = 6): boolean {
  if (!ts) return true;
  return Date.now() - new Date(ts).getTime() > hours * 3_600_000;
}

/** Vertical arrow connector between topology rows. */
function Connector({ label }: { label?: string }) {
  return (
    <div className="flex flex-col items-center text-surface-600 select-none">
      {label && <span className="text-[10px] font-mono text-surface-500">{label}</span>}
      <span className="leading-none">▼</span>
    </div>
  );
}

/** P0–P3 count chips for a set of shared tasks. */
function PriorityChips({ tasks }: { tasks: Array<{ priority: string | null }> }) {
  const counts: Record<string, number> = { P0: 0, P1: 0, P2: 0, P3: 0 };
  for (const t of tasks) if (t.priority && counts[t.priority] !== undefined) counts[t.priority] += 1;
  return (
    <div className="flex gap-1.5 flex-wrap">
      {(['P0', 'P1', 'P2', 'P3'] as const).map((p) => (
        <span
          key={p}
          className={`text-xs font-mono px-1.5 py-0.5 rounded border border-surface-700 bg-surface-800/50 ${getPriorityColor(p)}`}
        >
          {p}·{counts[p]}
        </span>
      ))}
    </div>
  );
}

export function CrossForgeTopology() {
  const { data: status } = useGetXmemStatusQuery(undefined, { pollingInterval: 30000 });
  const { data: ws } = useGetWorkspacesQuery(undefined, { pollingInterval: POLL });
  const { data: focus } = useGetXmemCurrentFocusQuery(undefined, { pollingInterval: POLL });
  const { data: claimable } = useGetSharedTasksQuery({ status: 'claimable' }, { pollingInterval: POLL });
  const { data: claimed } = useGetSharedTasksQuery({ status: 'claimed' }, { pollingInterval: POLL });
  const { data: completed } = useGetSharedTasksQuery({ status: 'completed' }, { pollingInterval: SLOW_POLL });
  const { data: linear } = useGetLinearCrossrefQuery(undefined, { pollingInterval: SLOW_POLL });

  const hubLive = !!status?.memory?.enabled && status.memory.backend !== 'noop';
  const me = status?.memory?.agentId;

  // ── Local forge: workspaces by open-task count (freshness gives counts free) ──
  const workspaces = (ws?.workspaces ?? [])
    .slice()
    .sort((a, b) => (b.freshness?.openTaskCount ?? 0) - (a.freshness?.openTaskCount ?? 0));
  const activeWsCount = workspaces.filter((w) => w.freshness?.active).length;
  const myFocus = me ? focus?.agents?.[me] : null;

  // ── Teammate forges (hub observations only) ──
  const focusAgents = focus?.agents ?? {};
  const idleAgents = focus?.idleAgents ?? [];
  const teammates = Array.from(new Set([...Object.keys(focusAgents), ...idleAgents]))
    .filter((a) => a && a !== me);

  // ── Orchestration pool ──
  const pool = claimable?.sharedTasks ?? [];
  const claimedTasks = claimed?.sharedTasks ?? [];
  const completedCount = completed?.sharedTasks?.length ?? 0;

  // ── Live pool ↔ Linear cross-reference ──
  const tickets = linear?.tickets ?? {};
  const pooledSka = Array.from(
    new Set(pool.map((t) => t.title.match(SKA_RE)?.[0]).filter((x): x is string => !!x)),
  ).sort();
  const pooledStatuses = pooledSka.map((id) => ({ id, status: tickets[id]?.status ?? null }));
  const staleInPool = pooledStatuses.filter((t) => t.status && TERMINAL.has(t.status));
  const doneTickets = Object.values(tickets)
    .filter((t) => t.status === 'Done')
    .map((t) => t.id)
    .sort();
  const linearStale = isStale(linear?.scrapedAt);
  const hasLinear = (linear?.ticketCount ?? 0) > 0;

  return (
    <section className="mt-8 space-y-2 animate-fade-in">
      {/* Header */}
      <div className="flex items-center gap-3">
        <Network className="w-5 h-5 text-fuchsia-400" />
        <h2 className="text-sm font-medium text-surface-200 uppercase tracking-wider">
          Cross-Forge Topology
        </h2>
        <span className="text-xs text-surface-500 font-mono">
          {status ? `team=${status.memory.teamId}` : 'connecting…'}
        </span>
        <span
          className={`ml-auto text-xs font-mono uppercase px-2 py-0.5 rounded border ${
            hubLive && status?.health.ok
              ? 'bg-green-500/20 text-green-400 border-green-500/40'
              : 'bg-yellow-500/20 text-yellow-400 border-yellow-500/40'
          }`}
        >
          backend={status?.memory?.backend ?? '…'}
          {status && !status.health.ok && ' · ⚠'}
        </span>
      </div>

      {/* ── Linear lane ───────────────────────────────────────────── */}
      <div className="glass-light rounded-xl p-4">
        <div className="flex items-center gap-2 mb-2">
          <GitBranch className="w-4 h-4 text-purple-400" />
          <span className="text-xs font-medium text-surface-300 uppercase tracking-wider">
            Linear · linear.app/skalpel/team/SKA
          </span>
          <span className="text-[10px] text-surface-500 font-mono">source of truth (external)</span>
          <span
            className={`ml-auto text-[10px] font-mono px-1.5 py-0.5 rounded border ${
              !hasLinear
                ? 'bg-surface-700/50 text-surface-400 border-surface-700'
                : linearStale
                  ? 'bg-amber-500/15 text-amber-400 border-amber-500/40'
                  : 'bg-green-500/15 text-green-400 border-green-500/40'
            }`}
          >
            {hasLinear ? `scraped ${formatRelativeTime(linear!.scrapedAt!)}${linearStale ? ' · stale' : ''}` : 'no scrape'}
          </span>
        </div>
        {!hasLinear ? (
          <p className="text-xs text-surface-500">
            No snapshot yet — run <span className="font-mono text-surface-300">npm run build:linear-crossref</span> after a CDP scrape.
          </p>
        ) : (
          <div className="grid grid-cols-1 sm:grid-cols-3 gap-2 text-xs">
            <div className="rounded-lg bg-surface-800/50 border border-surface-700 p-2">
              <div className="text-surface-400 mb-1">Your pooled SKA tickets</div>
              {pooledSka.length === 0 ? (
                <span className="text-surface-500">none in pool</span>
              ) : staleInPool.length === 0 ? (
                <span className="text-green-400 flex items-center gap-1">
                  <CheckCircle2 className="w-3.5 h-3.5" /> {pooledSka.length} · all open ✓
                </span>
              ) : (
                <span className="text-red-400 flex items-center gap-1">
                  <AlertTriangle className="w-3.5 h-3.5" /> {staleInPool.length} already done — pull from pool
                </span>
              )}
              <div className="mt-1 font-mono text-[10px] text-surface-500 break-words">
                {pooledSka.join(' · ') || '—'}
              </div>
            </div>
            <div className="rounded-lg bg-surface-800/50 border border-surface-700 p-2">
              <div className="text-surface-400 mb-1">Done in Linear</div>
              <span className="text-surface-200">{doneTickets.length}</span>
              <div className="mt-1 font-mono text-[10px] text-surface-500 break-words">
                {doneTickets.join(' · ') || '—'}
              </div>
            </div>
            <div className="rounded-lg bg-surface-800/50 border border-surface-700 p-2">
              <div className="text-surface-400 mb-1">Pool ↔ done overlap</div>
              <span className={staleInPool.length ? 'text-red-400' : 'text-green-400'}>
                {staleInPool.length === 0 ? 'NONE ✓' : staleInPool.map((t) => t.id).join(' · ')}
              </span>
              <div className="mt-1 text-[10px] text-surface-500">{linear?.ticketCount ?? 0} tickets in snapshot</div>
            </div>
          </div>
        )}
      </div>

      <Connector label="read-only cross-ref" />

      {/* ── Hub bar ───────────────────────────────────────────────── */}
      <div className="glass rounded-xl p-3 flex items-center gap-3">
        <Database className={`w-5 h-5 ${hubLive ? 'text-cyan-400' : 'text-surface-500'}`} />
        <span className="text-sm text-surface-200 font-medium">Skalpel Hub</span>
        <span className="text-xs text-surface-500 font-mono">AWS RDS · pgvector</span>
        <span
          className={`ml-auto flex items-center gap-1.5 text-xs font-mono ${
            hubLive && status?.health.ok ? 'text-green-400' : 'text-yellow-400'
          }`}
        >
          <span className={`status-dot ${hubLive && status?.health.ok ? 'in_progress' : 'waiting'}`} />
          {hubLive ? (status?.health.ok ? 'healthy' : status?.health.detail ?? 'degraded') : 'offline'}
        </span>
      </div>

      <Connector />

      {/* ── Two forges ────────────────────────────────────────────── */}
      <div className="grid grid-cols-1 lg:grid-cols-2 gap-3">
        {/* Local forge */}
        <div className="glass-light rounded-xl p-4">
          <div className="flex items-center gap-2 mb-2">
            <Boxes className="w-4 h-4 text-green-400" />
            <span className="text-xs font-medium text-surface-300 uppercase tracking-wider">Your forge</span>
            <span className="text-[10px] text-surface-500 font-mono truncate">{me ?? 'local'}</span>
            <span className="ml-auto text-[10px] text-surface-500 font-mono">
              {workspaces.length} ws · {activeWsCount} active
            </span>
          </div>
          <div className="mb-2 text-xs flex items-center gap-1.5">
            <span className={`status-dot ${myFocus ? 'in_progress' : 'waiting'}`} />
            <span className="text-surface-300">
              {myFocus ? (
                <>working: <span className="text-surface-100">{myFocus.currentTaskTitle}</span></>
              ) : (
                'idle'
              )}
            </span>
          </div>
          <div className="space-y-1 max-h-44 overflow-y-auto">
            {workspaces.slice(0, 8).map((w) => (
              <div key={w.id} className="flex items-center gap-2 text-xs">
                <span className={`w-1.5 h-1.5 rounded-full ${w.freshness?.active ? 'bg-green-500' : 'bg-surface-600'}`} />
                <span className="text-surface-200 truncate">{w.name}</span>
                {w.id === ws?.currentWorkspaceId && (
                  <span className="text-[9px] text-fuchsia-400 font-mono">◀ active</span>
                )}
                <span className="ml-auto font-mono text-surface-400">{w.freshness?.openTaskCount ?? 0}</span>
              </div>
            ))}
            {workspaces.length > 8 && (
              <div className="text-[10px] text-surface-500 pt-1">+{workspaces.length - 8} more workspaces</div>
            )}
          </div>
        </div>

        {/* Teammate forges */}
        <div className="glass-light rounded-xl p-4">
          <div className="flex items-center gap-2 mb-2">
            <Users className="w-4 h-4 text-blue-400" />
            <span className="text-xs font-medium text-surface-300 uppercase tracking-wider">Teammate forges</span>
            <span className="ml-auto text-[10px] text-surface-500 font-mono">hub observations only</span>
          </div>
          {!hubLive ? (
            <p className="text-xs text-surface-500">hub offline — teammates not visible</p>
          ) : teammates.length === 0 ? (
            <p className="text-xs text-surface-500">no teammates seen on the hub yet</p>
          ) : (
            <div className="space-y-1.5">
              {teammates.map((agent) => {
                const f = focusAgents[agent];
                return (
                  <div key={agent} className="flex items-center gap-2 text-xs">
                    <span className={`status-dot ${f ? 'in_progress' : 'waiting'}`} />
                    <span className="text-surface-200 font-mono truncate">{agent}</span>
                    <span className="ml-auto text-surface-400 truncate max-w-[55%]">
                      {f ? f.currentTaskTitle : 'idle · 0 claims'}
                    </span>
                  </div>
                );
              })}
            </div>
          )}
          <p className="mt-2 text-[10px] text-surface-600">
            local task content never crosses the hub boundary
          </p>
        </div>
      </div>

      <Connector />

      {/* ── Two planes ────────────────────────────────────────────── */}
      <div className="grid grid-cols-1 lg:grid-cols-2 gap-3">
        {/* Memory plane */}
        <div className="glass-light rounded-xl p-4">
          <div className="flex items-center gap-2 mb-2">
            <Layers className="w-4 h-4 text-blue-400" />
            <span className="text-xs font-medium text-surface-300 uppercase tracking-wider">Memory plane</span>
            <span className="ml-auto text-[10px] text-surface-500 font-mono">team_memory_events · metadata-only</span>
          </div>
          <div className="text-xs space-y-1">
            <div className="flex items-center gap-2">
              <span className="text-surface-400">current focus:</span>
              <span className="text-surface-200">
                {focus ? `${focus.count} working · ${(focus.idleAgents?.length ?? 0)} idle` : '…'}
              </span>
            </div>
            {focus && Object.entries(focusAgents).length > 0 ? (
              Object.entries(focusAgents).map(([agent, f]) =>
                f ? (
                  <div key={agent} className="flex items-center gap-2 pl-2">
                    <CircleDot className="w-3 h-3 text-green-400" />
                    <span className="font-mono text-surface-400 truncate">{agent.split('@')[0]}</span>
                    <span className="text-surface-300 truncate">{f.currentTaskTitle}</span>
                  </div>
                ) : null,
              )
            ) : (
              <div className="pl-2 text-surface-500">— everyone idle</div>
            )}
          </div>
        </div>

        {/* Orchestration plane */}
        <div className="glass-light rounded-xl p-4">
          <div className="flex items-center gap-2 mb-2">
            <Zap className="w-4 h-4 text-amber-400" />
            <span className="text-xs font-medium text-surface-300 uppercase tracking-wider">Orchestration plane</span>
            <span className="ml-auto text-[10px] text-surface-500 font-mono">shared_tasks · claimable pool</span>
          </div>
          <div className="grid grid-cols-3 gap-2 mb-2 text-center">
            <div className="rounded-lg bg-surface-800/50 border border-surface-700 p-2">
              <div className="text-lg font-display text-amber-400">{pool.length}</div>
              <div className="text-[10px] text-surface-500 uppercase">claimable</div>
            </div>
            <div className="rounded-lg bg-surface-800/50 border border-surface-700 p-2">
              <div className="text-lg font-display text-green-400">{claimedTasks.length}</div>
              <div className="text-[10px] text-surface-500 uppercase">claimed</div>
            </div>
            <div className="rounded-lg bg-surface-800/50 border border-surface-700 p-2">
              <div className="text-lg font-display text-surface-300">{completedCount}</div>
              <div className="text-[10px] text-surface-500 uppercase">completed</div>
            </div>
          </div>
          <div className="flex items-center gap-2">
            <span className="text-[10px] text-surface-500 uppercase">pool priorities</span>
            <div className="ml-auto"><PriorityChips tasks={pool} /></div>
          </div>
          {pooledSka.length > 0 && (
            <div className="mt-2 text-[10px] text-surface-500">
              {pooledSka.length} Linear-tracked ({pooledSka.join(', ')}) ·{' '}
              {staleInPool.length === 0 ? (
                <span className="text-green-400">all open ✓</span>
              ) : (
                <span className="text-red-400">⚠ {staleInPool.length} done in Linear</span>
              )}
            </div>
          )}
        </div>
      </div>
    </section>
  );
}
