import { useCallback, useEffect, useMemo, useState } from "react";
import { useQuery } from "@tanstack/react-query";
import { Files, GitBranch, Layers, Receipt } from "lucide-react";
import { Dialog, DialogContent } from "@/components/ui/dialog";
import { EmptyState } from "@/components/ui/empty-state";
import { ErrorState } from "@/components/ui/error-state";
import { Card, CardContent } from "@/components/ui/card";
import { KpiCard } from "@/components/KpiCard";
import { PageHeader } from "@/components/PageHeader";
import { BatchesList, BatchesListSkeleton } from "@/components/BatchesList";
import {
  BatchDetailContent,
  BatchDetailError,
  BatchDetailSkeleton,
  batchErrorKind,
} from "@/components/BatchDetail";
import { useBatches } from "@/hooks/useBatches";
import { useDrawerKeyboard } from "@/hooks/useDrawerKeyboard";
import { api, ApiError, type BatchSummary } from "@/lib/api";
import { cn } from "@/lib/utils";
import { fmt } from "@/lib/format";
import type { ParseResult837, ParseResult835 } from "@/types";

function readBatchId(): string | null {
  const params = new URLSearchParams(window.location.search);
  const value = params.get("batch");
  return value === "" ? null : value;
}

function buildBatchUrl(batchId: string | null): string {
  const url = new URL(window.location.href);
  if (batchId === null) {
    url.searchParams.delete("batch");
  } else {
    url.searchParams.set("batch", batchId);
  }
  return url.pathname + url.search + url.hash;
}

function useBatchDrawerUrlState(): {
  batchId: string | null;
  open: (id: string) => void;
  close: () => void;
  setBatchId: (id: string) => void;
} {
  const [batchId, setBatchIdState] = useState<string | null>(() => readBatchId());

  const open = useCallback((id: string) => {
    window.history.pushState(null, "", buildBatchUrl(id));
    setBatchIdState(id);
  }, []);

  const setBatchId = useCallback((id: string) => {
    window.history.replaceState(null, "", buildBatchUrl(id));
    setBatchIdState(id);
  }, []);

  const close = useCallback(() => {
    window.history.pushState(null, "", buildBatchUrl(null));
    setBatchIdState(null);
  }, []);

  useEffect(() => {
    const onPopState = () => setBatchIdState(readBatchId());
    window.addEventListener("popstate", onPopState);
    return () => window.removeEventListener("popstate", onPopState);
  }, []);

  return { batchId, open, close, setBatchId };
}

function useBatchDetail(id: string | null): {
  data: (ParseResult837 | ParseResult835) | null;
  isLoading: boolean;
  isError: boolean;
  error: Error | null;
  refetch: () => void;
} {
  const q = useQuery<ParseResult837 | ParseResult835>({
    queryKey: ["batch-detail", id],
    queryFn: async () => {
      try {
        return await api.getBatch(id as string);
      } catch (err) {
        if (
          err instanceof Error &&
          err.message.startsWith("404")
        ) {
          throw new ApiError(404, err.message);
        }
        throw err;
      }
    },
    enabled: id !== null,
    staleTime: 30 * 1000,
    retry: (failureCount, error) => {
      if (error instanceof ApiError && error.status === 404) return false;
      return failureCount < 3;
    },
  });

  if (id === null) {
    return {
      data: null,
      isLoading: false,
      isError: false,
      error: null,
      refetch: () => {},
    };
  }

  return {
    data: q.data ?? null,
    isLoading: q.isLoading,
    isError: q.isError,
    error: q.error,
    refetch: () => {
      void q.refetch();
    },
  };
}

const HELP_NOOP = () => {};

/**
 * Batches page — dark instrument treatment, in the same chrome
 * language as Dashboard / Upload / Reconciliation / Acks.
 *
 * PageHeader hero (eyebrow + display title + status pill + ghost
 * watermark) → KpiCard strip (4 tiles) → single Card wrapping the
 * tabular register → quiet hairline footer.
 *
 * Click a row to open the detail drawer (rendered above the page,
 * dimmed via the body opacity). Keyboard: ← / → step through
 * batches while the drawer is open; Esc closes.
 */
export function Batches() {
  const { data, isLoading, isError, error, refetch } = useBatches(100);
  const items: BatchSummary[] = data ?? [];

  const { batchId, open, close, setBatchId } = useBatchDrawerUrlState();

  const { data: detail, isLoading: detailLoading, error: detailError, refetch: refetchDetail } =
    useBatchDetail(batchId);

  const { onNext, onPrev } = useMemo(() => {
    if (batchId === null || items.length === 0) {
      return { onNext: () => {}, onPrev: () => {} };
    }
    const idx = items.findIndex((b) => b.id === batchId);
    if (idx === -1) return { onNext: () => {}, onPrev: () => {} };
    return {
      onNext: () => {
        const nextId = items[(idx + 1) % items.length].id;
        setBatchId(nextId);
      },
      onPrev: () => {
        const prevId = items[(idx - 1 + items.length) % items.length].id;
        setBatchId(prevId);
      },
    };
  }, [batchId, items, setBatchId]);

  useDrawerKeyboard({
    enabled: batchId !== null,
    onNext,
    onPrev,
    onClose: close,
    onToggleHelp: HELP_NOOP,
  });

  const dimBackground = batchId !== null;
  const errKind = batchErrorKind(detailError);

  // -----------------------------------------------------------------
  // Aggregate metrics for the KPI strip + hero copy.
  // -----------------------------------------------------------------
  const totals = items.reduce(
    (acc, b) => ({
      count: acc.count + 1,
      p837: acc.p837 + (b.kind === "837p" ? 1 : 0),
      p835: acc.p835 + (b.kind === "835" ? 1 : 0),
      claims: acc.claims + b.claimCount,
    }),
    { count: 0, p837: 0, p835: 0, claims: 0 },
  );

  const lastParsed = items[0]?.parsedAt;

  // The ghost watermark carries the on-file count, scaled like the
  // other pages (clamp 72–140px, 4.5% opacity, right-anchored).
  const watermark = totals.count > 0 ? totals.count.toLocaleString() : "BATCH";

  // -----------------------------------------------------------------
  // Stagger choreography — hero lands first, KPI strip at 140ms,
  // register at 240ms, footer at 320ms. Total < 500ms.
  // -----------------------------------------------------------------
  const heroDelay = 0;
  const kpiDelay = 140;
  const tableDelay = 240;
  const footerDelay = 320;

  return (
    <>
      <Dialog
        open={batchId !== null}
        onOpenChange={(open) => {
          if (!open) close();
        }}
      >
        <DialogContent
          className="fixed right-0 top-0 h-full w-full max-w-2xl translate-x-0 translate-y-0 rounded-none border-l border-border bg-card p-0"
          data-testid="batch-detail-drawer"
          aria-describedby={undefined}
        >
          {batchId === null ? null : detailLoading ? (
            <BatchDetailSkeleton />
          ) : errKind ? (
            <BatchDetailError
              kind={errKind}
              onRetry={() => {
                void refetchDetail();
              }}
              onClose={close}
            />
          ) : detail ? (
            <BatchDetailContent data={detail} onClose={close} />
          ) : null}
        </DialogContent>
      </Dialog>

      <div
        data-testid="batches-page-body"
        className={cn(
          "space-y-6 lg:space-y-10 animate-fade-in transition-opacity",
          dimBackground && "pointer-events-none opacity-60",
        )}
      >
        {/* =================================================================
            HERO — dark editorial header
            ================================================================= */}
        <section
          className="relative animate-fade-in overflow-hidden"
          style={{ animationDelay: `${heroDelay}ms` }}
        >
          <div
            aria-hidden="true"
            className="pointer-events-none select-none absolute -right-4 top-1/2 -translate-y-1/2 whitespace-nowrap display text-foreground"
            style={{
              fontSize: "clamp(72px, 12vw, 140px)",
              letterSpacing: "-0.04em",
              opacity: 0.045,
              lineHeight: 1,
            }}
          >
            {watermark}
          </div>

          <div className="relative z-10 flex items-end justify-between gap-4 sm:gap-6 flex-wrap">
            <div className="min-w-0">
              <PageHeader
                eyebrow={`Batches · Register · ${totals.count} on file`}
                title={
                  <>
                    Parsed{" "}
                    <span className="italic text-muted-foreground/85">
                      batches.
                    </span>
                  </>
                }
                subtitle={
                  <>
                    Every 837P and 835 file the backend has ingested. Click a
                    row for envelope, summary, and a peek at the contained
                    claims.
                  </>
                }
              />
            </div>
            <div className="inline-flex items-center gap-2 rounded-full border border-border/60 bg-card/60 px-3 py-1.5 text-[11px] mono uppercase tracking-[0.12em] text-muted-foreground backdrop-blur">
              <span className="relative inline-flex h-1.5 w-1.5 rounded-full bg-[hsl(var(--accent))]">
                <span className="absolute inline-flex h-full w-full rounded-full bg-[hsl(var(--accent))] opacity-60 animate-ping" />
              </span>
              <Files className="h-3.5 w-3.5" strokeWidth={1.75} />
              837P · 835 · envelope &amp; summary
            </div>
          </div>
        </section>

        {/* =================================================================
            KPI STRIP — four standard KpiCards, accent tokens instead of
            paper-tinted custom tiles.
            ================================================================= */}
        <section
          aria-label="Batch register metrics"
          className="grid gap-3.5 grid-cols-2 md:grid-cols-4 animate-fade-in-up"
          style={{ animationDelay: `${kpiDelay}ms` }}
        >
          <KpiCard
            label="On file"
            value={fmt.num(totals.count)}
            icon={Layers}
            accent="default"
            hint={totals.count === 1 ? "batch" : "batches"}
          />
          <KpiCard
            label="837P"
            value={fmt.num(totals.p837)}
            icon={GitBranch}
            accent="accent"
            hint="professional claims"
          />
          <KpiCard
            label="835"
            value={fmt.num(totals.p835)}
            icon={Receipt}
            accent="warning"
            hint="remittance advice"
          />
          <KpiCard
            label="Claims"
            value={fmt.num(totals.claims)}
            accent="success"
            hint="total in register"
          />
        </section>

        {/* =================================================================
            REGISTER — single Card wrapping the tabular list. Same
            chrome language as the rest of the app: eyebrow + display
            title + sidecar hint, dark-tone table.
            ================================================================= */}
        <section
          aria-label="Batch register"
          className="animate-fade-in-up"
          style={{ animationDelay: `${tableDelay}ms` }}
        >
          <Card>
            <CardContent className="p-6 lg:p-7 space-y-5">
              <div className="flex items-end justify-between gap-6 flex-wrap">
                <div className="min-w-0">
                  <div className="eyebrow flex items-center gap-2 mb-2">
                    <span className="inline-block h-px w-6 bg-foreground/20" />
                    The register
                  </div>
                  <h2 className="display text-[26px] leading-[1.05] tracking-[-0.02em]">
                    All <span className="italic">ingests</span>, newest first.
                  </h2>
                </div>
                <p className="text-[12.5px] text-muted-foreground/80 max-w-sm">
                  Tap a row to open the envelope drawer. Use{" "}
                  <kbd className="rounded-sm border border-border/60 bg-card/40 px-1.5 py-0.5 not-italic text-foreground/80 mono text-[10.5px] uppercase tracking-[0.14em]">
                    ←
                  </kbd>{" "}
                  /{" "}
                  <kbd className="rounded-sm border border-border/60 bg-card/40 px-1.5 py-0.5 not-italic text-foreground/80 mono text-[10.5px] uppercase tracking-[0.14em]">
                    →
                  </kbd>{" "}
                  inside the drawer to step.
                </p>
              </div>

              <div className="pt-5 border-t border-border/40">
                {isError ? (
                  <ErrorState
                    message="Couldn't load batches from the backend."
                    detail={error instanceof Error ? error.message : String(error)}
                    onRetry={() => refetch()}
                  />
                ) : isLoading ? (
                  <BatchesListSkeleton />
                ) : items.length === 0 ? (
                  <div className="rounded-md border border-dashed border-border/60 bg-card/40">
                    <EmptyState
                      eyebrow="Batches · awaiting first ingest"
                      message="Upload an 837P or 835 file on the Upload page to populate this list."
                    />
                  </div>
                ) : (
                  <div className="rounded-md border border-border/60 overflow-hidden bg-card/40">
                    <BatchesList
                      items={items}
                      openId={batchId}
                      onOpen={open}
                    />
                  </div>
                )}
              </div>
            </CardContent>
          </Card>
        </section>

        {/* =================================================================
            FOOTER — single hairline-separated status row. Replaces the
            warm-paper "End of register" treatment with a quiet
            instrument-style status line in the same rhythm as the
            other pages.
            ================================================================= */}
        <section
          aria-label="Register status"
          className="animate-fade-in-up flex items-center justify-between gap-4 flex-wrap pt-5 border-t border-border/40"
          style={{ animationDelay: `${footerDelay}ms` }}
        >
          <div className="flex items-center gap-2 mono text-[10.5px] uppercase tracking-[0.18em] text-muted-foreground/60">
            <span className="h-1.5 w-1.5 rounded-full bg-[hsl(var(--accent))]" />
            Cyclone · Batches
          </div>
          <div className="flex items-center gap-3 mono text-[10.5px] uppercase tracking-[0.18em] text-muted-foreground/60">
            <span>
              {totals.count} {totals.count === 1 ? "row" : "rows"}
            </span>
            <span className="text-muted-foreground/30" aria-hidden>
              ·
            </span>
            <span>last parsed {lastParsed ? fmt.dateShort(lastParsed) : "—"}</span>
          </div>
          <div className="flex items-center gap-1.5 mono text-[10.5px] uppercase tracking-[0.18em] text-muted-foreground/60">
            <span>open drawer</span>
            <kbd className="rounded-sm border border-border/60 bg-card/40 px-1.5 py-0.5 not-italic text-foreground/80">
              ↩
            </kbd>
          </div>
        </section>
      </div>
    </>
  );
}
