import {
  type ReactNode,
  useCallback,
  useEffect,
  useMemo,
  useState,
} from "react";
import "./App.css";
import { isDashboardConfigured, supabase } from "./lib/supabase";

type TaskStatus = "pending" | "assigned" | "running" | "completed" | "failed";
type ActivityType = "reserve" | "release" | "transfer";
type NodeRole = "provider" | "requester" | "both";
type NodeStatus = "online" | "offline";
type NodeHealth = "healthy" | "stale" | "offline" | "never-seen";

type BalanceSummary = {
  available_credits: number;
  reserved_credits: number;
  total_credits: number;
};

type NetworkSummary = {
  generated_at: string;
  runtime_mode: string;
  healthy_window_seconds: number;
  nodes: {
    total: number;
    online: number;
    offline: number;
    healthy: number;
    stale: number;
    providers: number;
    requesters: number;
    healthy_providers: number;
    healthy_requesters: number;
    last_heartbeat_at: string | null;
  };
  tasks: {
    pending: number;
    assigned: number;
    running: number;
    completed: number;
    failed: number;
    created_24h: number;
    completed_24h: number;
    failed_24h: number;
    success_rate_24h: number;
    queued_budget: number;
    oldest_pending_age_seconds: number;
    longest_running_age_seconds: number;
  };
  balances: BalanceSummary;
  economy: {
    credits_reserved_24h: number;
    credits_released_24h: number;
    credits_transferred_24h: number;
    last_transaction_at: string | null;
  };
  performance: {
    avg_eval_ms_24h: number;
    avg_billed_mflops_24h: number;
  };
};

type PublicTask = {
  id: string;
  status: TaskStatus;
  type: string;
  model: string;
  credit_budget: number;
  attempt_count: number;
  max_attempts: number;
  requester_name: string;
  provider_name: string;
  prompt_preview: string;
  created_at: string;
  started_at: string | null;
  completed_at: string | null;
  failed_at: string | null;
  billed_mflops: number;
  generated_tokens: number;
  total_eval_ms: number;
  last_error: string;
};

type PublicActivity = {
  id: string;
  type: ActivityType;
  amount: number;
  memo: string;
  task_id: string | null;
  from_node_name: string;
  to_node_name: string;
  created_at: string;
};

type PublicNode = {
  id: string;
  name: string;
  role: NodeRole;
  status: NodeStatus;
  last_heartbeat: string | null;
  health: NodeHealth;
  accelerator: string;
  gpu_name: string;
  gpu_count: number;
  memory_gb: number;
  created_at: string;
};

type PublicLemma = {
  id: string;
  conjecture: string;
  normalized_code: string;
  verification_summary: string;
  compiler: string;
  source_prompt: string;
  stored_at: string;
};

type DashboardData = {
  runtimeMode: string;
  summary: NetworkSummary;
  tasks: PublicTask[];
  activity: PublicActivity[];
  nodes: PublicNode[];
  lemmas: PublicLemma[];
};

type SegmentTone = "default" | "success" | "warning" | "danger" | "accent";

type ChartSegment = {
  label: string;
  value: number;
  tone: SegmentTone;
  valueLabel: string;
};

type ComparisonRow = {
  label: string;
  value: number;
  tone: SegmentTone;
  valueLabel: string;
  detail?: string;
};

const REFRESH_OPTIONS = [5000, 10000, 30000, 60000];
const numberFormatter = new Intl.NumberFormat("en-US");
const CREDIT_SCALE = 1_000_000;

function demoCredits(value: number): number {
  return value * CREDIT_SCALE;
}

const demoData: DashboardData = {
  runtimeMode: "reservation-v1",
  summary: {
    generated_at: "2026-03-09T17:45:00Z",
    runtime_mode: "reservation-v1",
    healthy_window_seconds: 120,
    nodes: {
      total: 8,
      online: 6,
      offline: 2,
      healthy: 5,
      stale: 3,
      providers: 5,
      requesters: 6,
      healthy_providers: 4,
      healthy_requesters: 3,
      last_heartbeat_at: "2026-03-09T17:44:51Z",
    },
    tasks: {
      pending: 3,
      assigned: 1,
      running: 2,
      completed: 142,
      failed: 7,
      created_24h: 31,
      completed_24h: 26,
      failed_24h: 2,
      success_rate_24h: 92.9,
      queued_budget: demoCredits(21),
      oldest_pending_age_seconds: 384,
      longest_running_age_seconds: 147,
    },
    balances: {
      available_credits: demoCredits(94),
      reserved_credits: demoCredits(21),
      total_credits: demoCredits(115),
    },
    economy: {
      credits_reserved_24h: demoCredits(65),
      credits_released_24h: demoCredits(9),
      credits_transferred_24h: demoCredits(56),
      last_transaction_at: "2026-03-09T17:44:42Z",
    },
    performance: {
      avg_eval_ms_24h: 18240.21,
      avg_billed_mflops_24h: demoCredits(1.28),
    },
  },
  tasks: [
    {
      id: "7cb66fc2-771f-4757-b17c-0d3706f051f3",
      status: "running",
      type: "lean_proof_gen",
      model: "bartowski/DeepSeek-R1-Distill-Llama-8B-GGUF",
      credit_budget: demoCredits(3),
      attempt_count: 1,
      max_attempts: 3,
      requester_name: "proof-lab-1",
      provider_name: "cuda-worker-2",
      prompt_preview:
        "Prove in Lean that if n divides a and n divides b, then n divides a + b.",
      created_at: "2026-03-09T17:42:15Z",
      started_at: "2026-03-09T17:42:57Z",
      completed_at: null,
      failed_at: null,
      billed_mflops: 0,
      generated_tokens: 0,
      total_eval_ms: 0,
      last_error: "",
    },
    {
      id: "81b9545c-9c0c-42af-a86d-06c9df1d8177",
      status: "completed",
      type: "lean_proof_gen",
      model: "bartowski/DeepSeek-R1-Distill-Llama-8B-GGUF",
      credit_budget: demoCredits(2),
      attempt_count: 1,
      max_attempts: 3,
      requester_name: "lean-demo",
      provider_name: "mps-node-1",
      prompt_preview: "Show in Lean that True implies True.",
      created_at: "2026-03-09T17:35:10Z",
      started_at: "2026-03-09T17:35:21Z",
      completed_at: "2026-03-09T17:35:38Z",
      failed_at: null,
      billed_mflops: demoCredits(1),
      generated_tokens: 198,
      total_eval_ms: 16624.8,
      last_error: "",
    },
    {
      id: "9289b0e4-435f-444c-9834-8f52bbf44cb6",
      status: "pending",
      type: "lean_proof_gen",
      model: "bartowski/Qwen2.5-Coder-7B-Instruct-GGUF",
      credit_budget: demoCredits(2),
      attempt_count: 0,
      max_attempts: 3,
      requester_name: "batch-requester",
      provider_name: "unassigned",
      prompt_preview:
        "Formalize that the composition of injective functions is injective.",
      created_at: "2026-03-09T17:38:52Z",
      started_at: null,
      completed_at: null,
      failed_at: null,
      billed_mflops: 0,
      generated_tokens: 0,
      total_eval_ms: 0,
      last_error: "",
    },
    {
      id: "13bb7113-ff98-4c02-a6c0-66e1dcaac268",
      status: "failed",
      type: "lean_proof_gen",
      model: "bartowski/DeepSeek-R1-Distill-Llama-8B-GGUF",
      credit_budget: demoCredits(1),
      attempt_count: 3,
      max_attempts: 3,
      requester_name: "proof-lab-2",
      provider_name: "cpu-worker-1",
      prompt_preview:
        "Construct a Lean proof that every finite subgroup of a cyclic group is cyclic.",
      created_at: "2026-03-09T16:58:11Z",
      started_at: "2026-03-09T17:03:19Z",
      completed_at: null,
      failed_at: "2026-03-09T17:09:42Z",
      billed_mflops: 0,
      generated_tokens: 0,
      total_eval_ms: 0,
      last_error: "Task lease expired and retry budget was exhausted.",
    },
    {
      id: "2d4da01e-746f-4037-9be7-8e916c7df8f8",
      status: "assigned",
      type: "lean_proof_gen",
      model: "bartowski/DeepSeek-R1-Distill-Llama-8B-GGUF",
      credit_budget: demoCredits(1),
      attempt_count: 1,
      max_attempts: 3,
      requester_name: "queue-tester",
      provider_name: "cuda-worker-1",
      prompt_preview:
        "Give a Lean proof that multiplication on naturals is associative.",
      created_at: "2026-03-09T17:41:03Z",
      started_at: null,
      completed_at: null,
      failed_at: null,
      billed_mflops: 0,
      generated_tokens: 0,
      total_eval_ms: 0,
      last_error: "",
    },
  ],
  activity: [
    {
      id: "7a4d256a-a2e2-4be6-b2b0-81b99d8c8211",
      type: "transfer",
      amount: demoCredits(1),
      memo: "Task completion settlement",
      task_id: "81b9545c-9c0c-42af-a86d-06c9df1d8177",
      from_node_name: "lean-demo",
      to_node_name: "mps-node-1",
      created_at: "2026-03-09T17:35:38Z",
    },
    {
      id: "7a4d256a-a2e2-4be6-b2b0-81b99d8c8212",
      type: "release",
      amount: demoCredits(1),
      memo: "Unused task reservation released",
      task_id: "81b9545c-9c0c-42af-a86d-06c9df1d8177",
      from_node_name: "network",
      to_node_name: "lean-demo",
      created_at: "2026-03-09T17:35:38Z",
    },
    {
      id: "7a4d256a-a2e2-4be6-b2b0-81b99d8c8213",
      type: "reserve",
      amount: demoCredits(2),
      memo: "Task budget reserved",
      task_id: "9289b0e4-435f-444c-9834-8f52bbf44cb6",
      from_node_name: "batch-requester",
      to_node_name: "network",
      created_at: "2026-03-09T17:38:52Z",
    },
    {
      id: "7a4d256a-a2e2-4be6-b2b0-81b99d8c8214",
      type: "reserve",
      amount: demoCredits(1),
      memo: "Task budget reserved",
      task_id: "2d4da01e-746f-4037-9be7-8e916c7df8f8",
      from_node_name: "queue-tester",
      to_node_name: "network",
      created_at: "2026-03-09T17:41:03Z",
    },
  ],
  nodes: [
    {
      id: "7418988a-5f59-4d4a-aa1d-f88f36a330ce",
      name: "cuda-worker-1",
      role: "provider",
      status: "online",
      last_heartbeat: "2026-03-09T17:44:51Z",
      health: "healthy",
      accelerator: "cuda",
      gpu_name: "RTX 4090",
      gpu_count: 1,
      memory_gb: 24,
      created_at: "2026-03-09T15:10:00Z",
    },
    {
      id: "30ce1de1-b440-45bf-98f9-a387e30de0c4",
      name: "cuda-worker-2",
      role: "provider",
      status: "online",
      last_heartbeat: "2026-03-09T17:44:33Z",
      health: "healthy",
      accelerator: "cuda",
      gpu_name: "RTX 4080",
      gpu_count: 1,
      memory_gb: 16,
      created_at: "2026-03-09T15:20:00Z",
    },
    {
      id: "7d98b70e-2084-45ad-91f3-1a1735064954",
      name: "mps-node-1",
      role: "both",
      status: "online",
      last_heartbeat: "2026-03-09T17:44:40Z",
      health: "healthy",
      accelerator: "mps",
      gpu_name: "Apple Silicon",
      gpu_count: 1,
      memory_gb: 32,
      created_at: "2026-03-09T15:30:00Z",
    },
    {
      id: "5b7d6b9f-9272-46d0-bf12-3adb67d627c4",
      name: "cpu-worker-1",
      role: "provider",
      status: "online",
      last_heartbeat: "2026-03-09T17:40:01Z",
      health: "stale",
      accelerator: "cpu",
      gpu_name: "No dedicated GPU detected",
      gpu_count: 0,
      memory_gb: 64,
      created_at: "2026-03-09T15:40:00Z",
    },
    {
      id: "8c41d523-0930-4311-bfcb-10d6ad1b1fd3",
      name: "proof-lab-1",
      role: "requester",
      status: "online",
      last_heartbeat: "2026-03-09T17:43:48Z",
      health: "healthy",
      accelerator: "unknown",
      gpu_name: "Requester node",
      gpu_count: 0,
      memory_gb: 0,
      created_at: "2026-03-09T15:50:00Z",
    },
  ],
  lemmas: [
    {
      id: "af25118e-3aba-45c6-bcfe-37b32c0c93ef",
      conjecture: "For all propositions P, a proof of P implies P.",
      normalized_code: `lemma proof_implies_truth (P : Prop) : P -> P := by
  intro h
  exact h`,
      verification_summary:
        "Lean accepted the normalized proof with no remaining goals.",
      compiler: "Lean 4.15.0",
      source_prompt:
        "Show in Lean that any proposition implies itself once assumed.",
      stored_at: "2026-03-09T17:35:38Z",
    },
    {
      id: "7a90095d-f0c5-4f61-8b95-c7203f5db54a",
      conjecture: "If n divides a and n divides b, then n divides a + b.",
      normalized_code: `lemma dvd_add_of_dvd_dvd {n a b : Nat} (ha : n ∣ a) (hb : n ∣ b) : n ∣ a + b := by
  rcases ha with ⟨k, rfl⟩
  rcases hb with ⟨l, rfl⟩
  exact ⟨k + l, by ring⟩`,
      verification_summary:
        "Normalized theorem compiled successfully and preserved the intended arithmetic statement.",
      compiler: "Lean 4.15.0",
      source_prompt:
        "Prove in Lean that divisibility is preserved under addition.",
      stored_at: "2026-03-09T17:29:11Z",
    },
  ],
};

async function fetchDashboardData(): Promise<DashboardData> {
  if (!supabase) {
    return demoData;
  }

  const [
    runtimeModeResponse,
    summaryResponse,
    tasksResponse,
    activityResponse,
    nodesResponse,
    lemmasResponse,
  ] = await Promise.all([
    supabase.rpc("get_runtime_mode"),
    supabase.rpc("get_public_network_summary"),
    supabase.rpc("get_public_recent_tasks", { p_limit: 12 }),
    supabase.rpc("get_public_recent_activity", { p_limit: 8 }),
    supabase.rpc("get_public_nodes", { p_limit: 8 }),
    supabase.rpc("get_public_verified_lemmas", { p_limit: 6 }),
  ]);

  const errors = [
    summaryResponse.error,
    tasksResponse.error,
    activityResponse.error,
    nodesResponse.error,
    lemmasResponse.error,
  ].filter(Boolean);

  if (errors.length > 0) {
    throw new Error(
      errors.map((error) => error?.message ?? "Unknown error").join(" | "),
    );
  }

  if (!summaryResponse.data) {
    throw new Error("Network summary RPC returned no data");
  }

  if (typeof runtimeModeResponse.data !== "string") {
    throw new Error("Runtime mode RPC returned no data");
  }

  const runtimeMode = runtimeModeResponse.data;

  return {
    runtimeMode,
    summary: summaryResponse.data as NetworkSummary,
    tasks: (tasksResponse.data ?? []) as PublicTask[],
    activity: (activityResponse.data ?? []) as PublicActivity[],
    nodes: (nodesResponse.data ?? []) as PublicNode[],
    lemmas: (lemmasResponse.data ?? []) as PublicLemma[],
  };
}

function App() {
  const [dashboard, setDashboard] = useState<DashboardData | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const [isRefreshing, setIsRefreshing] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [refreshInterval, setRefreshInterval] = useState(10000);

  const loadDashboard = useCallback(async (silent = false) => {
    if (silent) {
      setIsRefreshing(true);
    } else {
      setIsLoading(true);
    }

    try {
      const nextData = await fetchDashboardData();
      setDashboard(nextData);
      setError(null);
    } catch (fetchError) {
      const message =
        fetchError instanceof Error
          ? fetchError.message
          : "Unknown dashboard error";
      setError(message);
    } finally {
      setIsLoading(false);
      setIsRefreshing(false);
    }
  }, []);

  useEffect(() => {
    void loadDashboard(false);
  }, [loadDashboard]);

  useEffect(() => {
    const timer = window.setInterval(() => {
      void loadDashboard(true);
    }, refreshInterval);

    return () => window.clearInterval(timer);
  }, [loadDashboard, refreshInterval]);

  const summary = dashboard?.summary;
  const liveMode = isDashboardConfigured();
  const runtimeMode = dashboard?.runtimeMode ?? "reservation-v1";
  const balanceSummary = useMemo(() => getBalanceSummary(summary), [summary]);
  const recentTasks = useMemo(
    () => (dashboard?.tasks ?? []).slice(0, 4),
    [dashboard],
  );
  const latestActivity = useMemo(
    () => (dashboard?.activity ?? []).slice(0, 4),
    [dashboard],
  );
  const recentLemmas = useMemo(
    () => (dashboard?.lemmas ?? []).slice(0, 4),
    [dashboard],
  );
  const featuredProviders = useMemo(
    () =>
      (dashboard?.nodes ?? [])
        .filter((node) => node.role === "provider" || node.role === "both")
        .filter((node) => node.health === "healthy")
        .slice(0, 4),
    [dashboard],
  );

  const proofPoints = useMemo(() => {
    if (!summary) {
      return [];
    }

    return [
      {
        label: "Healthy providers",
        value: `${summary.nodes.healthy_providers}`,
        detail: "ready to claim work now",
      },
      {
        label: "24h completed tasks",
        value: `${numberFormatter.format(summary.tasks.completed_24h)}`,
        detail: "formal work settled recently",
      },
      {
        label: "24h compute paid",
        value: formatCompactCompute(summary.economy.credits_transferred_24h),
        detail: "settled to providers in the last day",
      },
      {
        label: "Average billed work",
        value: formatCompactCompute(summary.performance.avg_billed_mflops_24h),
        detail: "per completed task in the last 24h",
      },
    ];
  }, [summary]);

  const activeTaskCount = useMemo(
    () =>
      summary
        ? summary.tasks.pending + summary.tasks.assigned + summary.tasks.running
        : 0,
    [summary],
  );

  const fleetSegments = useMemo<ChartSegment[]>(() => {
    if (!summary) {
      return [];
    }

    const healthy = summary.nodes.healthy;
    const onlineLate = Math.max(
      summary.nodes.online - summary.nodes.healthy,
      0,
    );
    const offline = summary.nodes.offline;
    const other = Math.max(
      summary.nodes.total - healthy - onlineLate - offline,
      0,
    );

    const segments: ChartSegment[] = [
      {
        label: "Healthy",
        value: healthy,
        tone: "success",
        valueLabel: `${healthy}`,
      },
      {
        label: "Online but late",
        value: onlineLate,
        tone: "warning",
        valueLabel: `${onlineLate}`,
      },
      {
        label: "Offline",
        value: offline,
        tone: "danger",
        valueLabel: `${offline}`,
      },
      {
        label: "Other",
        value: other,
        tone: "default",
        valueLabel: `${other}`,
      },
    ];

    return segments.filter((segment) => segment.value > 0);
  }, [summary]);

  const computeSegments = useMemo<ChartSegment[]>(
    () => [
      {
        label: "Available now",
        value: balanceSummary.available_credits,
        tone: "success",
        valueLabel: formatCompactCompute(balanceSummary.available_credits),
      },
      {
        label: "Reserved now",
        value: balanceSummary.reserved_credits,
        tone: "accent",
        valueLabel: formatCompactCompute(balanceSummary.reserved_credits),
      },
    ],
    [balanceSummary],
  );

  const queueSegments = useMemo<ChartSegment[]>(
    () =>
      summary
        ? [
            {
              label: "Queued",
              value: summary.tasks.pending,
              tone: "warning",
              valueLabel: `${summary.tasks.pending}`,
            },
            {
              label: "Leased",
              value: summary.tasks.assigned,
              tone: "accent",
              valueLabel: `${summary.tasks.assigned}`,
            },
            {
              label: "Running",
              value: summary.tasks.running,
              tone: "success",
              valueLabel: `${summary.tasks.running}`,
            },
          ]
        : [],
    [summary],
  );

  const settlementRows = useMemo<ComparisonRow[]>(
    () =>
      summary
        ? [
            {
              label: "Reserved",
              value: summary.economy.credits_reserved_24h,
              tone: "accent",
              valueLabel: formatCompactCompute(
                summary.economy.credits_reserved_24h,
              ),
              detail: "held aside for queued or leased work",
            },
            {
              label: "Paid out",
              value: summary.economy.credits_transferred_24h,
              tone: "success",
              valueLabel: formatCompactCompute(
                summary.economy.credits_transferred_24h,
              ),
              detail: "measured compute settled to providers",
            },
            {
              label: "Returned",
              value: summary.economy.credits_released_24h,
              tone: "warning",
              valueLabel: formatCompactCompute(
                summary.economy.credits_released_24h,
              ),
              detail: "unused compute budget sent back",
            },
          ]
        : [],
    [summary],
  );

  const networkNarrative = useMemo(() => {
    if (!summary) {
      return "Loading the current network state...";
    }

    const reservedShare =
      balanceSummary.total_credits > 0
        ? Math.round(
            (balanceSummary.reserved_credits / balanceSummary.total_credits) *
              100,
          )
        : 0;

    return `${summary.nodes.healthy_providers} healthy providers can claim work right now. ${activeTaskCount} tasks are active, and ${formatCompactCompute(balanceSummary.reserved_credits)} (${reservedShare}%) of tracked compute is currently reserved.`;
  }, [activeTaskCount, balanceSummary, summary]);

  return (
    <main className="app-shell landing-shell">
      <section className="hero-section">
        <div className="hero-copy-block">
          <div className="hero-topline">
            <span className="eyebrow">Research Capacitor</span>
            <span className={`pill ${liveMode ? "pill-live" : "pill-demo"}`}>
              {liveMode ? "Live network" : "Demo preview"}
            </span>
          </div>
          <h1>
            Turn spare compute into a network for automated math research.
          </h1>
          <p className="hero-copy hero-copy-large">
            Research Capacitor is a compute marketplace for Lean 4 and
            proof-generation workloads. Researchers submit high-level jobs with
            a clear budget, the backend keeps a repair loop running, providers
            execute local `llama.cpp` inference, and the network settles every
            queued attempt with explicit reserve, transfer, and release steps.
          </p>

          <div className="hero-actions">
            <a className="button-primary" href="#network">
              See the network
            </a>
            <a className="button-secondary" href="#get-started">
              Get started
            </a>
          </div>

          <div className="proof-grid">
            {proofPoints.map((item) => (
              <article key={item.label} className="proof-card">
                <strong>{item.value}</strong>
                <span>{item.label}</span>
                <p>{item.detail}</p>
              </article>
            ))}
          </div>
        </div>

        <aside className="hero-panel">
          <div className="hero-panel-header">
            <div>
              <p className="eyebrow">Why it matters</p>
              <h2>A shared compute layer for proof generation</h2>
            </div>
          </div>

          <div className="hero-panel-copy">
            <p>
              Instead of asking every lab or hacker to build a one-off pipeline,
              Research Capacitor turns proof work into a backend-managed queue
              of episodes and repair attempts that any compatible machine can
              help process.
            </p>
            <p>
              The important part is accountability: compute is shown directly in
              TFLOPs, providers are paid on measured model work, and failed or
              partial runs release held budget back automatically.
            </p>
          </div>

          <dl className="metric-list compact-metrics">
            <MetricRow
              label="Available compute"
              value={formatCompactCompute(balanceSummary.available_credits)}
              tooltip="Compute budget currently free to fund new queued or leased work."
            />
            <MetricRow
              label="Reserved now"
              value={formatCompactCompute(balanceSummary.reserved_credits)}
              tooltip="Compute already held for queued tasks, leased work, or active runs."
            />
            <MetricRow
              label="24h success rate"
              value={
                summary
                  ? `${summary.tasks.success_rate_24h.toFixed(1)}%`
                  : "..."
              }
            />
            <MetricRow
              label="Avg eval time"
              value={
                summary
                  ? formatEvalMs(summary.performance.avg_eval_ms_24h)
                  : "..."
              }
            />
            <MetricRow
              label="Last heartbeat"
              value={
                summary
                  ? formatRelativeTime(summary.nodes.last_heartbeat_at)
                  : "..."
              }
            />
          </dl>

          <button
            className="button-ghost"
            onClick={() => void loadDashboard(true)}
            disabled={isRefreshing}
          >
            {isRefreshing
              ? "Refreshing live data..."
              : "Refresh network snapshot"}
          </button>
        </aside>
      </section>

      {!liveMode ? (
        <section className="banner banner-info">
          <strong>Demo data is showing.</strong> Add `VITE_SUPABASE_URL` and
          `VITE_SUPABASE_ANON_KEY` to switch the homepage to live network data.
        </section>
      ) : null}

      {error ? (
        <section className="banner banner-error">
          <strong>Dashboard fetch failed:</strong> {error}
        </section>
      ) : null}

      <section id="network" className="section-block">
        <SectionIntro
          eyebrow="Live network"
          title="A quick read on fleet health, queue pressure, and compute flow."
          body="The dashboard below uses TFLOPs throughout, so you can quickly see how much compute is free, how much is already committed, and whether work is moving cleanly through the network."
        />

        <div className="toolbar toolbar-simple">
          <div className="toolbar-meta">
            <span>
              Updated {formatRelativeTime(summary?.generated_at ?? null)}
            </span>
            <span>
              {isLoading ? "Loading snapshot..." : "Auto-refresh active"}
            </span>
            <span>Mode {runtimeMode}</span>
          </div>

          <label className="refresh-picker">
            Refresh
            <select
              value={refreshInterval}
              onChange={(event) =>
                setRefreshInterval(Number(event.target.value))
              }
            >
              {REFRESH_OPTIONS.map((option) => (
                <option key={option} value={option}>
                  {option / 1000}s
                </option>
              ))}
            </select>
          </label>
        </div>

        <div className="network-summary-card">
          <p className="eyebrow">At a glance</p>
          <p className="network-summary-copy">{networkNarrative}</p>
        </div>

        <div className="overview-grid">
          <ChartCard
            title="Fleet health"
            tooltip="Healthy nodes have checked in within the current heartbeat window. Online but late nodes are still connected, but their last heartbeat is old enough to make them risky for new work."
          >
            <strong className="chart-card-value">
              {summary
                ? `${summary.nodes.healthy}/${Math.max(summary.nodes.online, 1)} online healthy`
                : "..."}
            </strong>
            <p className="chart-card-copy">
              {summary
                ? `${summary.nodes.total} total nodes · last heartbeat ${formatRelativeTime(summary.nodes.last_heartbeat_at)}`
                : "..."}
            </p>
            <StackedBar segments={fleetSegments} />
            <div className="chart-legend">
              {fleetSegments.map((segment) => (
                <div key={segment.label} className="legend-row">
                  <span className={`legend-dot tone-${segment.tone}`} />
                  <span>{segment.label}</span>
                  <strong>{segment.valueLabel}</strong>
                </div>
              ))}
            </div>
          </ChartCard>

          <ChartCard
            title="Compute available"
            tooltip="This compares tracked compute that is still free against compute already reserved for queued, leased, or active work."
          >
            <strong className="chart-card-value">
              {summary
                ? formatCompactCompute(balanceSummary.total_credits)
                : "..."}
            </strong>
            <p className="chart-card-copy">
              {summary
                ? `${formatCompactCompute(balanceSummary.available_credits)} free · ${formatCompactCompute(balanceSummary.reserved_credits)} reserved`
                : "..."}
            </p>
            <StackedBar segments={computeSegments} />
            <div className="chart-legend">
              {computeSegments.map((segment) => (
                <div key={segment.label} className="legend-row">
                  <span className={`legend-dot tone-${segment.tone}`} />
                  <span>{segment.label}</span>
                  <strong>{segment.valueLabel}</strong>
                </div>
              ))}
            </div>
          </ChartCard>

          <ChartCard
            title="Active work"
            tooltip="Queued work is waiting for a provider, leased work has been claimed, and running work is actively consuming compute."
          >
            <strong className="chart-card-value">
              {summary ? `${activeTaskCount} active tasks` : "..."}
            </strong>
            <p className="chart-card-copy">
              {summary
                ? `${formatDuration(summary.tasks.oldest_pending_age_seconds)} oldest queued · ${formatDuration(summary.tasks.longest_running_age_seconds)} longest run`
                : "..."}
            </p>
            <StackedBar segments={queueSegments} />
            <div className="chart-legend">
              {queueSegments.map((segment) => (
                <div key={segment.label} className="legend-row">
                  <span className={`legend-dot tone-${segment.tone}`} />
                  <span>{segment.label}</span>
                  <strong>{segment.valueLabel}</strong>
                </div>
              ))}
              <div className="legend-row">
                <span className="legend-dot tone-success" />
                <span>Completed 24h</span>
                <strong>
                  {summary
                    ? numberFormatter.format(summary.tasks.completed_24h)
                    : "..."}
                </strong>
              </div>
              <div className="legend-row">
                <span className="legend-dot tone-danger" />
                <span>Failed 24h</span>
                <strong>
                  {summary
                    ? numberFormatter.format(summary.tasks.failed_24h)
                    : "..."}
                </strong>
              </div>
            </div>
          </ChartCard>

          <ChartCard
            title="24h compute flow"
            tooltip="Reserved compute is budget held up front, paid out compute is settled to providers, and returned compute is released back to requesters."
          >
            <strong className="chart-card-value">
              {summary
                ? formatCompactCompute(summary.economy.credits_transferred_24h)
                : "..."}
            </strong>
            <p className="chart-card-copy">
              {summary
                ? `paid to providers in the last 24 hours · ${summary.tasks.success_rate_24h.toFixed(1)}% success rate`
                : "..."}
            </p>
            <ComparisonBars rows={settlementRows} />
          </ChartCard>
        </div>

        <div className="panel-grid">
          <Panel
            title="Recent tasks"
            subtitle="Live proof-generation work moving through the queue"
          >
            <div className="task-list">
              {recentTasks.map((task) => (
                <article key={task.id} className="task-card">
                  <div className="task-card-head">
                    <span className={`pill ${statusClass(task.status)}`}>
                      {statusLabel(task.status)}
                    </span>
                    <span className="task-age">
                      {formatRelativeTime(task.started_at ?? task.created_at)}
                    </span>
                  </div>
                  <div className="primary-cell">{task.prompt_preview}</div>
                  <div className="secondary-cell">
                    {task.requester_name}
                    {task.provider_name !== "unassigned"
                      ? ` -> ${task.provider_name}`
                      : " -> waiting for provider"}
                  </div>
                  <div className="task-card-meta">
                    <span>{describeTaskSettlement(task)}</span>
                    <span>
                      {task.status === "completed"
                        ? formatEvalMs(task.total_eval_ms)
                        : leaseOrModelText(task)}
                    </span>
                  </div>
                </article>
              ))}
              {recentTasks.length === 0 ? (
                <EmptyState message="No recent tasks yet." />
              ) : null}
            </div>
          </Panel>

          <Panel
            title="Recent settlement"
            subtitle="Compute being held, paid out, and returned across the network"
          >
            <div className="timeline">
              {latestActivity.map((entry) => (
                <div key={entry.id} className="timeline-item">
                  <span className={`pill ${activityClass(entry.type)}`}>
                    {activityLabel(entry.type)}
                  </span>
                  <div className="timeline-copy">
                    <div className="primary-cell">{`${entry.from_node_name} -> ${entry.to_node_name}`}</div>
                    <div className="secondary-cell">
                      {formatCompactCompute(entry.amount)} ·{" "}
                      {entry.memo || "Settlement update"} ·{" "}
                      {formatRelativeTime(entry.created_at)}
                    </div>
                  </div>
                </div>
              ))}
              {latestActivity.length === 0 ? (
                <EmptyState message="No recent settlement activity yet." />
              ) : null}
            </div>
          </Panel>
        </div>

        <div className="panel-grid">
          <Panel
            title="Proven lemmas"
            subtitle="Recently verified Lean statements captured by the network"
          >
            <div className="lemma-list">
              {recentLemmas.map((lemma) => (
                <article key={lemma.id} className="lemma-card">
                  <div className="lemma-card-head">
                    <span className="pill pill-completed">proven</span>
                    <span className="task-age">
                      {formatRelativeTime(lemma.stored_at)}
                    </span>
                  </div>
                  <div className="primary-cell">{lemma.conjecture}</div>
                  <div className="secondary-cell">
                    {lemma.verification_summary ||
                      "Verified by Lean and stored in the public lemma archive."}
                  </div>
                  {lemma.normalized_code ? (
                    <pre className="lemma-code">
                      {previewLemmaCode(lemma.normalized_code)}
                    </pre>
                  ) : null}
                  <div className="lemma-card-meta">
                    <span>{lemma.compiler || "Lean compiler"}</span>
                    <span>
                      {lemma.source_prompt ||
                        "Formal proof generated by the network"}
                    </span>
                  </div>
                </article>
              ))}
              {recentLemmas.length === 0 ? (
                <EmptyState message="No proven lemmas have been published yet." />
              ) : null}
            </div>
          </Panel>

          <Panel
            title="Provider fleet"
            subtitle="Healthy providers currently visible on the network"
          >
            <div className="provider-grid">
              {featuredProviders.map((node) => (
                <article key={node.id} className="provider-card">
                  <div className="provider-card-head">
                    <strong>{node.name}</strong>
                    <span className="pill pill-live">{node.accelerator}</span>
                  </div>
                  <p>{node.gpu_name}</p>
                  <span>
                    {node.gpu_count > 0 ? `${node.gpu_count} GPU` : "CPU-only"}{" "}
                    · {node.memory_gb || 0} GB memory
                  </span>
                </article>
              ))}
              {featuredProviders.length === 0 ? (
                <EmptyState message="No healthy providers are visible yet." />
              ) : null}
            </div>
          </Panel>
        </div>

        <Panel
          title="How to read this"
          subtitle="Plain-language definitions for the numbers above"
        >
          <dl className="metric-list compact-metrics">
            <MetricRow
              label="Compute unit"
              value="1 TFLOP"
              tooltip="All user-facing compute accounting in this dashboard is expressed directly in TFLOPs."
            />
            <MetricRow
              label="Queued compute"
              value={
                summary
                  ? formatCompactCompute(summary.tasks.queued_budget)
                  : "..."
              }
              tooltip="Compute already committed to queued or leased work that has not fully settled yet."
            />
            <MetricRow
              label="Reserved 24h"
              value={
                summary
                  ? formatCompactCompute(summary.economy.credits_reserved_24h)
                  : "..."
              }
              tooltip="Total compute budget held aside over the last 24 hours."
            />
            <MetricRow
              label="Returned 24h"
              value={
                summary
                  ? formatCompactCompute(summary.economy.credits_released_24h)
                  : "..."
              }
              tooltip="Unused compute budget released back to requesters over the last 24 hours."
            />
            <MetricRow
              label="Oldest queued"
              value={
                summary
                  ? formatDuration(summary.tasks.oldest_pending_age_seconds)
                  : "..."
              }
              tooltip="How long the oldest still-waiting task has been sitting in queue."
            />
            <MetricRow
              label="Healthy window"
              value={
                summary ? formatDuration(summary.healthy_window_seconds) : "..."
              }
              tooltip="How recent a node heartbeat must be before the dashboard counts that node as healthy."
            />
          </dl>
        </Panel>
      </section>

      <section id="get-started" className="cta-section">
        <div className="cta-copy">
          <p className="eyebrow">Get started</p>
          <h2>Launch a node or submit proof work in minutes.</h2>
          <p>
            The repo already documents the full path: initialize a node, run `rc
            serve`, and submit backend-managed Lean research jobs with large
            explicit budgets.
          </p>
        </div>

        <div className="command-grid">
          <article className="command-card">
            <h3>Run as a provider</h3>
            <pre>{`rc init --name "provider-1" --role provider
rc serve --poll-interval 2 --max-tokens 256`}</pre>
          </article>
          <article className="command-card">
            <h3>Submit research</h3>
            <pre>{`rc init --name "requester-1" --role requester
rc research-run --total-budget 25 --budget-per-attempt 1`}</pre>
          </article>
        </div>
      </section>
    </main>
  );
}

function Panel(props: {
  title: string;
  subtitle: string;
  children: ReactNode;
}) {
  return (
    <section className="panel">
      <div className="panel-header">
        <div>
          <h2>{props.title}</h2>
          <p>{props.subtitle}</p>
        </div>
      </div>
      {props.children}
    </section>
  );
}

function SectionIntro(props: { eyebrow: string; title: string; body: string }) {
  return (
    <div className="section-intro">
      <p className="eyebrow">{props.eyebrow}</p>
      <h2>{props.title}</h2>
      <p>{props.body}</p>
    </div>
  );
}

function ChartCard(props: {
  title: string;
  tooltip: string;
  children: ReactNode;
}) {
  return (
    <article className="chart-card">
      <div className="chart-card-header">
        <TooltipLabel label={props.title} tooltip={props.tooltip} />
      </div>
      {props.children}
    </article>
  );
}

function TooltipLabel(props: { label: string; tooltip: string }) {
  return (
    <span className="label-with-tooltip">
      <span>{props.label}</span>
      <span className="tooltip-chip" tabIndex={0}>
        ?
        <span className="tooltip-bubble" role="tooltip">
          {props.tooltip}
        </span>
      </span>
    </span>
  );
}

function StackedBar(props: { segments: ChartSegment[] }) {
  const visibleSegments = props.segments.filter((segment) => segment.value > 0);
  const total = visibleSegments.reduce(
    (sum, segment) => sum + segment.value,
    0,
  );

  return (
    <div className="stacked-bar" aria-hidden="true">
      {visibleSegments.length === 0 || total <= 0 ? (
        <span className="stacked-bar-empty" />
      ) : null}
      {visibleSegments.map((segment) => (
        <span
          key={segment.label}
          className={`stacked-bar-segment tone-${segment.tone}`}
          style={{ width: `${(segment.value / total) * 100}%` }}
        />
      ))}
    </div>
  );
}

function ComparisonBars(props: { rows: ComparisonRow[] }) {
  const maxValue = props.rows.reduce((max, row) => Math.max(max, row.value), 0);

  return (
    <div className="comparison-bars">
      {props.rows.map((row) => {
        const width =
          maxValue > 0
            ? Math.max((row.value / maxValue) * 100, row.value > 0 ? 8 : 0)
            : 0;
        return (
          <div key={row.label} className="comparison-row">
            <div className="comparison-row-head">
              <span>{row.label}</span>
              <strong>{row.valueLabel}</strong>
            </div>
            <div className="comparison-track" aria-hidden="true">
              <span
                className={`comparison-fill tone-${row.tone}`}
                style={{ width: `${width}%` }}
              />
            </div>
            {row.detail ? (
              <span className="comparison-detail">{row.detail}</span>
            ) : null}
          </div>
        );
      })}
    </div>
  );
}

function MetricRow(props: { label: string; value: string; tooltip?: string }) {
  return (
    <>
      <dt>
        {props.tooltip ? (
          <TooltipLabel label={props.label} tooltip={props.tooltip} />
        ) : (
          props.label
        )}
      </dt>
      <dd>{props.value}</dd>
    </>
  );
}

function EmptyState(props: { message: string }) {
  return <div className="empty-state">{props.message}</div>;
}

function getBalanceSummary(
  summary: NetworkSummary | undefined,
): BalanceSummary {
  const reserved = summary?.balances.reserved_credits ?? 0;
  const available = summary?.balances.available_credits ?? 0;
  const total = summary?.balances.total_credits ?? 0;
  return {
    available_credits: available,
    reserved_credits: reserved,
    total_credits: total,
  };
}

function describeTaskSettlement(task: PublicTask): string {
  const reserved = formatCompactCompute(task.credit_budget);
  const transferred = formatCompactCompute(task.billed_mflops);
  const released = formatCompactCompute(
    Math.max(task.credit_budget - task.billed_mflops, 0),
  );

  if (task.status === "completed") {
    return `${reserved} budget · ${transferred} paid · ${released} returned`;
  }

  if (task.status === "failed") {
    return `${reserved} returned after failure`;
  }

  return `${reserved} currently held`;
}

function leaseOrModelText(task: PublicTask): string {
  if (task.status === "assigned" || task.status === "running") {
    return "lease active";
  }

  if (task.status === "pending") {
    return "waiting for provider";
  }

  return task.model;
}

function previewLemmaCode(value: string): string {
  const lines = value
    .split("\n")
    .map((line) => line.trimEnd())
    .filter((line) => line.trim().length > 0);

  if (lines.length === 0) {
    return "Proof body unavailable.";
  }

  const preview = lines.slice(0, 4).join("\n");
  return lines.length > 4 ? `${preview}\n...` : preview;
}

function statusLabel(status: TaskStatus): string {
  switch (status) {
    case "assigned":
      return "leased";
    case "completed":
      return "settled";
    default:
      return status;
  }
}

function activityLabel(type: ActivityType): string {
  switch (type) {
    case "reserve":
      return "hold";
    case "release":
      return "return";
    case "transfer":
      return "pay";
    default:
      return type;
  }
}

function trimTrailingZeros(value: string): string {
  return value.includes(".") ? value.replace(/\.?0+$/, "") : value;
}

function formatCompactCompute(value: number): string {
  const tflops = value / CREDIT_SCALE;

  if (tflops >= 1_000_000_000) {
    return `${(tflops / 1_000_000_000).toFixed(1)}B TFLOPs`;
  }

  if (tflops >= 1_000_000) {
    return `${(tflops / 1_000_000).toFixed(1)}M TFLOPs`;
  }

  if (tflops >= 1_000) {
    return `${(tflops / 1_000).toFixed(1)}K TFLOPs`;
  }

  if (tflops >= 1) {
    return `${trimTrailingZeros(tflops.toFixed(3))} TFLOPs`;
  }

  return `${trimTrailingZeros(tflops.toFixed(6))} TFLOPs`;
}

function formatEvalMs(value: number): string {
  if (value <= 0) {
    return "n/a";
  }

  if (value >= 1000) {
    return `${(value / 1000).toFixed(1)}s`;
  }

  return `${Math.round(value)}ms`;
}

function formatDuration(seconds: number): string {
  if (!seconds || seconds <= 0) {
    return "0s";
  }

  if (seconds >= 3600) {
    return `${(seconds / 3600).toFixed(1)}h`;
  }

  if (seconds >= 60) {
    return `${Math.round(seconds / 60)}m`;
  }

  return `${Math.round(seconds)}s`;
}

function formatRelativeTime(value: string | null): string {
  if (!value) {
    return "n/a";
  }

  const timestamp = new Date(value).getTime();
  if (Number.isNaN(timestamp)) {
    return "n/a";
  }

  const diffSeconds = Math.round((Date.now() - timestamp) / 1000);
  if (diffSeconds < 5) {
    return "just now";
  }

  if (diffSeconds < 60) {
    return `${diffSeconds}s ago`;
  }

  const diffMinutes = Math.round(diffSeconds / 60);
  if (diffMinutes < 60) {
    return `${diffMinutes}m ago`;
  }

  const diffHours = Math.round(diffMinutes / 60);
  if (diffHours < 24) {
    return `${diffHours}h ago`;
  }

  return new Date(value).toLocaleString();
}

function statusClass(status: TaskStatus): string {
  return `pill-${status}`;
}

function activityClass(type: ActivityType): string {
  return `pill-${type}`;
}

export default App;
