// Two-snapshot fleet compare: pick two runs (A = baseline, B = comparison,
// defaulting to the latest two completed runs), see fleet totals side by
// side and the per-region deltas behind them. The run ids live in the URL
// (?runA&runB) so a comparison can be shared — and they flow unchanged into
// the per-region compare links.

"use client";

import { Suspense, useCallback, useEffect, useState } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import { comparePairQuery, fetchCompareOverview, fetchComparableRuns } from "@/lib/api-client";
import type { OverviewDiff, RunSummaryFile } from "@/lib/api-types";
import { usePolling } from "@/lib/use-polling";
import { Section } from "@/components/ui/Section";
import { Empty } from "@/components/ui/Empty";
import { Loading } from "@/components/ui/Loading";
import { ErrorBox } from "@/components/ui/ErrorBox";
import { Button } from "@/components/ui/Button";
import { CompareTotals } from "@/components/compare/CompareTotals";
import { RegionDeltaTable } from "@/components/compare/RegionDeltaTable";
import { RunSelect } from "@/components/compare/RunSelect";

export default function ComparePage() {
  // useSearchParams needs a Suspense boundary for static prerendering.
  return (
    <Suspense fallback={<Loading label="loading comparison…" />}>
      <CompareInner />
    </Suspense>
  );
}

/** Shareable compare URL for a run pair (encoding lives in
 *  comparePairQuery — see its comment). */
function compareUrl(a: string, b: string): string {
  return `/compare?${comparePairQuery(a, b)}`;
}

function CompareInner() {
  const search = useSearchParams();
  const router = useRouter();

  const [usable, setUsable] = useState<RunSummaryFile[] | null>(null);
  const [runA, setRunA] = useState<string | null>(null);
  const [runB, setRunB] = useState<string | null>(null);
  const [compare, setCompare] = useState<OverviewDiff | null>(null);
  const [error, setError] = useState<string | null>(null);

  const loadRuns = useCallback(async () => {
    try {
      setUsable(await fetchComparableRuns());
      setError(null);
    } catch (e) {
      setError(e instanceof Error ? e.message : String(e));
    }
  }, []);

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

  // Seed the selection from the URL once (an id outside the fetched usable
  // list falls back to the default). Functional updates make re-runs no-ops,
  // and the defaults never collide with an explicitly requested id on the
  // other side — only an explicit runA === runB yields a self-compare.
  useEffect(() => {
    if (usable === null) return;
    const valid = (id: string | null): string | null =>
      id !== null && usable.some((r) => r.runId === id) ? id : null;
    const aVal = valid(search.get("runA"));
    const bVal = valid(search.get("runB"));
    const defaultA = (): string | null => {
      for (const idx of [1, 0]) {
        const id = usable[idx]?.runId;
        if (id !== undefined && id !== bVal) return id;
      }
      return null;
    };
    const finalA = aVal ?? defaultA();
    const finalB = bVal ?? usable.find((r) => r.runId !== finalA)?.runId ?? null;
    setRunA((prev) => prev ?? finalA);
    setRunB((prev) => prev ?? finalB);
  }, [usable, search]);

  // The hook's sequence guard: a superseded fetch (rapid side changes) may
  // still be in flight — only the latest load writes state, so stale
  // responses can't overwrite the pair the selects now show.
  const load = useCallback(async (isCurrent: () => boolean) => {
    if (runA === null || runB === null) return;
    try {
      const r = await fetchCompareOverview(runA, runB);
      if (!isCurrent()) return;
      setCompare(r.compare);
      setError(null);
    } catch (e) {
      if (!isCurrent()) return;
      setError(e instanceof Error ? e.message : String(e));
      setCompare(null);
    }
  }, [runA, runB]);

  const { load: reload } = usePolling(load);

  const syncUrl = (a: string, b: string): void => {
    router.replace(compareUrl(a, b), { scroll: false });
  };

  const swap = (): void => {
    if (runA === null || runB === null) return;
    setRunA(runB);
    setRunB(runA);
    syncUrl(runB, runA);
  };

  return (
    <div className="animate-fade-in space-y-4">
      <h1 className="text-xl font-semibold tracking-tight">Compare</h1>

      {error ? (
        <ErrorBox
          message={error}
          onRetry={() => {
            void loadRuns();
            void reload();
          }}
        />
      ) : usable === null ? (
        <Loading label="loading runs…" />
      ) : usable.length < 2 ? (
        <Empty>Need at least two completed runs to compare — analyze the fleet first.</Empty>
      ) : runA !== null && runB !== null ? (
        <>
          <Section
            title="Snapshots"
            subtitle="each side uses that run's data — a region missing on a side falls back to its last snapshot at or before it"
          >
            <div className="flex flex-wrap items-center gap-4 text-sm">
              <RunSelect
                sideLabel="Snapshot A (baseline)"
                runs={usable}
                value={runA}
                otherValue={runB}
                onChange={(next) => {
                  setRunA(next);
                  syncUrl(next, runB);
                }}
              />
              <Button variant="secondary" size="sm" onClick={swap} aria-label="Swap sides">
                ⇄
              </Button>
              <RunSelect
                sideLabel="Snapshot B"
                runs={usable}
                value={runB}
                otherValue={runA}
                onChange={(next) => {
                  setRunB(next);
                  syncUrl(runA, next);
                }}
              />
            </div>
          </Section>

          {compare === null ? (
            <Loading label="comparing runs…" />
          ) : (
            <>
              <Section
                title="Fleet totals"
                subtitle={`A ${compare.runIdA} vs B ${compare.runIdB}`}
              >
                <CompareTotals diff={compare} />
              </Section>

              <Section
                title="Regions"
                subtitle="sorted by |cost Δ| — click a region for the nodegroup and workload diff"
              >
                <RegionDeltaTable diff={compare} />
              </Section>
            </>
          )}
        </>
      ) : null}
    </div>
  );
}
