"use client";
import { useState, useTransition } from "react";
import Link from "next/link";
import { Copy, Loader2, AlertTriangle, ExternalLink } from "lucide-react";
import {
  previewNearDupes,
  backfillPhashes,
  findNearDuplicates,
  type NearDupePair,
  type NearDupesPreview,
} from "@/app/actions/maintenance";
import { thumbUrl } from "@/lib/assetUrls";
import { useSettingsPanel } from "./SettingsPanelProvider";

type State =
  | { kind: "idle" }
  | { kind: "scanning" }
  | { kind: "preview"; data: NearDupesPreview }
  | { kind: "backfilling" }
  | { kind: "running" }
  | { kind: "result"; pairs: NearDupePair[] };

function fmtBytes(n: number): string {
  if (n < 1024) return `${n} B`;
  if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;
  return `${(n / 1024 / 1024).toFixed(2)} MB`;
}

export function NearDupesButton() {
  const [state, setState] = useState<State>({ kind: "idle" });
  const [pending, start] = useTransition();
  const [threshold, setThreshold] = useState(10);
  const { close: closeSettings } = useSettingsPanel();

  const scan = () => {
    setState({ kind: "scanning" });
    start(async () => {
      const data = await previewNearDupes();
      setState({ kind: "preview", data });
    });
  };

  const backfillAndFind = async () => {
    setState({ kind: "backfilling" });
    await backfillPhashes();
    setState({ kind: "running" });
    const pairs = await findNearDuplicates({ threshold });
    setState({ kind: "result", pairs });
  };

  const findOnly = async () => {
    setState({ kind: "running" });
    const pairs = await findNearDuplicates({ threshold });
    setState({ kind: "result", pairs });
  };

  return (
    <div className="py-2">
      <div className="flex items-start justify-between gap-4">
        <div className="min-w-0">
          <div className="text-sm font-medium">Find Near-Duplicate Covers</div>
          <div className="text-xs text-[var(--color-fg-muted)] mt-0.5">
            Compares perceptual hashes of every cover and surfaces pairs that look the same but
            aren&apos;t SHA-identical — different encodes, mild crops, or upscales of the same image.
            Complements the SHA dedup and code-collision detectors.
          </div>
          {state.kind === "preview" && (
            <div className="text-xs mt-2 text-[var(--color-fg-dim)] space-y-2">
              <div>
                <span className="font-mono text-[var(--color-cyan)]">{state.data.hashed}</span> hashed
                {" · "}
                <span className="font-mono text-[var(--color-amber,#fbbf24)]">{state.data.unhashed}</span> need backfill
                {" · "}of {state.data.total} covers
              </div>
              <div className="flex items-center gap-2">
                <label className="font-mono text-[10px] uppercase tracking-wider text-[var(--color-fg-muted)]">
                  Threshold
                </label>
                <input
                  type="range"
                  min={0}
                  max={20}
                  step={1}
                  value={threshold}
                  onChange={(e) => setThreshold(Number(e.target.value))}
                  className="flex-1 max-w-[200px] accent-[var(--color-cyan)]"
                />
                <span className="font-mono text-[var(--color-cyan)] tabular-nums w-8">{threshold}</span>
              </div>
              <div className="text-[11px] text-[var(--color-fg-muted)]">
                0 = identical · 5 = very tight · 10 = robust default · 20 = noisy
              </div>
            </div>
          )}
          {state.kind === "result" && (
            <div className="text-xs mt-2 flex items-center gap-1.5">
              {state.pairs.length === 0 ? (
                <span className="text-[var(--color-mint)]">No near-duplicate pairs found at this threshold.</span>
              ) : (
                <span className="text-[var(--color-coral)] flex items-center gap-1.5">
                  <AlertTriangle className="w-3.5 h-3.5" />
                  {state.pairs.length} near-duplicate pair{state.pairs.length === 1 ? "" : "s"} (distance ≤ {threshold}).
                </span>
              )}
            </div>
          )}
        </div>
        <div className="flex-shrink-0 flex items-center gap-2">
          {state.kind === "idle" && (
            <button
              onClick={scan}
              disabled={pending}
              className="inline-flex items-center justify-center gap-1.5 min-w-[100px] text-xs px-3 py-1.5 rounded-lg glass glass-hover text-[var(--color-fg-dim)] hover:text-[var(--color-fg)] whitespace-nowrap"
            >
              <Copy className="w-3.5 h-3.5" /> Scan
            </button>
          )}
          {(state.kind === "scanning" || state.kind === "backfilling" || state.kind === "running") && (
            <span className="flex items-center gap-1.5 text-xs text-[var(--color-fg-dim)]">
              <Loader2 className="w-3.5 h-3.5 animate-spin" />
              {state.kind === "scanning" ? "Counting…" : state.kind === "backfilling" ? "Hashing…" : "Comparing…"}
            </span>
          )}
          {state.kind === "preview" && (
            <>
              <button
                onClick={() => setState({ kind: "idle" })}
                className="inline-flex items-center justify-center min-w-[80px] text-xs px-3 py-1.5 rounded-lg text-[var(--color-fg-muted)] hover:text-[var(--color-fg)] hover:bg-[var(--color-glass)]"
              >
                Cancel
              </button>
              {state.data.unhashed > 0 ? (
                <button
                  onClick={() => start(() => backfillAndFind())}
                  disabled={pending}
                  className="inline-flex items-center justify-center gap-1.5 min-w-[100px] text-xs px-3 py-1.5 rounded-lg bg-[var(--color-cyan)]/15 text-[var(--color-cyan)] border border-[var(--color-cyan)]/40 hover:bg-[var(--color-cyan)]/25 disabled:opacity-40 whitespace-nowrap"
                >
                  Hash {state.data.unhashed} & find pairs
                </button>
              ) : (
                <button
                  onClick={() => start(() => findOnly())}
                  disabled={pending}
                  className="inline-flex items-center justify-center gap-1.5 min-w-[100px] text-xs px-3 py-1.5 rounded-lg bg-[var(--color-cyan)]/15 text-[var(--color-cyan)] border border-[var(--color-cyan)]/40 hover:bg-[var(--color-cyan)]/25 disabled:opacity-40 whitespace-nowrap"
                >
                  Find pairs
                </button>
              )}
            </>
          )}
          {state.kind === "result" && (
            <>
              <button
                onClick={scan}
                disabled={pending}
                className="inline-flex items-center justify-center gap-1.5 min-w-[100px] text-xs px-3 py-1.5 rounded-lg glass glass-hover text-[var(--color-fg-dim)] hover:text-[var(--color-fg)] whitespace-nowrap"
              >
                Re-scan
              </button>
              <button
                onClick={() => setState({ kind: "idle" })}
                className="inline-flex items-center justify-center min-w-[80px] text-xs px-3 py-1.5 rounded-lg text-[var(--color-fg-muted)] hover:text-[var(--color-fg)] hover:bg-[var(--color-glass)]"
              >
                Dismiss
              </button>
            </>
          )}
        </div>
      </div>

      {state.kind === "result" && state.pairs.length > 0 && (
        <div className="mt-3 max-h-96 overflow-y-auto rounded-md border border-[var(--color-glass-border)] bg-[var(--color-bg-1)]/40 divide-y divide-[var(--color-glass-border)]">
          {state.pairs.map((p) => {
            const aBigger = p.a.width * p.a.height >= p.b.width * p.b.height;
            const aMoreBytes = p.a.bytes >= p.b.bytes;
            return (
              <div key={`${p.a.id}-${p.b.id}`} className="p-2">
                <div className="flex items-center gap-2 mb-1.5">
                  <span className="font-mono text-[10px] uppercase tracking-wider px-1.5 py-0.5 rounded bg-[var(--color-coral)]/15 text-[var(--color-coral)]">
                    Δ {p.distance}
                  </span>
                  <span className="text-[11px] text-[var(--color-fg-muted)]">
                    Hamming distance — lower = more similar
                  </span>
                </div>
                <div className="grid grid-cols-2 gap-2">
                  <DupeCell side={p.a} bigger={aBigger} moreBytes={aMoreBytes} onNavigate={closeSettings} />
                  <DupeCell side={p.b} bigger={!aBigger} moreBytes={!aMoreBytes} onNavigate={closeSettings} />
                </div>
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
}

function DupeCell({
  side,
  bigger,
  moreBytes,
  onNavigate,
}: {
  side: NearDupePair["a"];
  bigger: boolean;
  moreBytes: boolean;
  onNavigate: () => void;
}) {
  return (
    <Link
      href={`/image/${side.id}`}
      onClick={onNavigate}
      className="flex items-center gap-2 rounded-md p-2 hover:bg-[var(--color-glass)] transition-colors"
    >
      {/* eslint-disable-next-line @next/next/no-img-element */}
      <img
        src={thumbUrl({ thumbPath: side.thumbPath, code: side.code, id: side.id })}
        alt=""
        className="w-12 h-12 object-contain bg-black/40 rounded shrink-0"
        loading="lazy"
      />
      <div className="min-w-0 flex-1">
        <div className="flex items-center gap-2 text-xs">
          {side.code ? (
            <span className="font-mono font-bold text-[var(--color-cyan)]">{side.code}</span>
          ) : (
            <span className="font-mono text-[var(--color-fg-muted)] italic">no code</span>
          )}
          <span className={`font-mono tabular-nums text-[11px] ${bigger ? "text-[var(--color-mint)]" : "text-[var(--color-fg-muted)]"}`}>
            {side.width}×{side.height}
          </span>
          <span className={`font-mono tabular-nums text-[11px] ${moreBytes ? "text-[var(--color-mint)]" : "text-[var(--color-fg-muted)]"}`}>
            {fmtBytes(side.bytes)}
          </span>
        </div>
        <div className="text-[11px] text-[var(--color-fg-dim)] truncate font-mono mt-0.5">
          {side.filename}
        </div>
      </div>
      <ExternalLink className="w-3.5 h-3.5 text-[var(--color-fg-muted)] shrink-0" />
    </Link>
  );
}
