"use client";
import { useEffect, useMemo, useState } from "react";
import { createPortal } from "react-dom";
import { X, Replace, SkipForward, ArrowUp, ArrowDown, Equal, Shuffle } from "lucide-react";
import { cn } from "@/lib/utils";

export type CollisionBucket = "upgrade" | "downgrade" | "sidegrade" | "mixed";
export type CollisionDecision = "replace" | "skip";

export interface CollisionReviewItem {
  jobId: string;
  filename: string;
  code: string | null;
  existingId: number;
  existingFilename: string;
  existingWidth: number;
  existingHeight: number;
  existingBytes: number;
  existingThumbPath: string;
  incomingWidth: number;
  incomingHeight: number;
  incomingBytes: number;
  bucket: CollisionBucket;
}

export interface CollisionReviewProps {
  items: CollisionReviewItem[];
  onCancel: () => void;
  onConfirm: (decisions: Record<string, CollisionDecision>) => void;
}

const BUCKET_META: Record<CollisionBucket, { label: string; icon: typeof ArrowUp; color: string; defaultDecision: CollisionDecision }> = {
  upgrade: { label: "Upgrade", icon: ArrowUp, color: "var(--color-mint)", defaultDecision: "replace" },
  downgrade: { label: "Downgrade", icon: ArrowDown, color: "var(--color-coral)", defaultDecision: "skip" },
  sidegrade: { label: "Sidegrade", icon: Equal, color: "var(--color-amber, #fbbf24)", defaultDecision: "skip" },
  mixed: { label: "Mixed", icon: Shuffle, color: "var(--color-violet)", defaultDecision: "skip" },
};

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 CollisionReviewDialog({ items, onCancel, onConfirm }: CollisionReviewProps) {
  const [decisions, setDecisions] = useState<Record<string, CollisionDecision>>(() => {
    const init: Record<string, CollisionDecision> = {};
    for (const it of items) init[it.jobId] = BUCKET_META[it.bucket].defaultDecision;
    return init;
  });

  useEffect(() => {
    const onKey = (e: KeyboardEvent) => { if (e.key === "Escape") onCancel(); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [onCancel]);

  const counts = useMemo(() => {
    const c: Record<CollisionBucket, number> = { upgrade: 0, downgrade: 0, sidegrade: 0, mixed: 0 };
    for (const it of items) c[it.bucket]++;
    return c;
  }, [items]);

  function applyToBucket(bucket: CollisionBucket | "all", decision: CollisionDecision) {
    setDecisions((s) => {
      const next = { ...s };
      for (const it of items) {
        if (bucket === "all" || it.bucket === bucket) next[it.jobId] = decision;
      }
      return next;
    });
  }

  const replaceCount = Object.values(decisions).filter((d) => d === "replace").length;
  const skipCount = items.length - replaceCount;

  if (typeof document === "undefined") return null;
  return createPortal(
    <div
      className="fixed inset-0 z-[100] flex items-center justify-center bg-black/70 backdrop-blur-sm"
      // Backdrop dismiss on mousedown (not click) so a text-drag-select
      // started inside the dialog and released over the backdrop doesn't
      // discard the user's review decisions.
      onMouseDown={(e) => { if (e.target === e.currentTarget) onCancel(); }}
    >
      <div
        onMouseDown={(e) => e.stopPropagation()}
        className="relative w-[min(95vw,900px)] max-h-[85vh] flex flex-col rounded-2xl border border-[var(--color-glass-border-strong)] bg-[var(--color-bg-0)] shadow-2xl"
      >
        <div className="px-5 py-4 border-b border-[var(--color-glass-border)] flex items-center justify-between">
          <div>
            <div className="text-base font-medium">Code collisions detected</div>
            <div className="text-xs text-[var(--color-fg-muted)] mt-0.5">
              {items.length} cover{items.length === 1 ? "" : "s"} share a code with an existing entry. Pick what to do with each.
            </div>
          </div>
          <button onClick={onCancel} className="text-[var(--color-fg-muted)] hover:text-[var(--color-fg)]">
            <X className="w-4 h-4" />
          </button>
        </div>

        <div className="px-5 py-3 border-b border-[var(--color-glass-border)] flex flex-wrap items-center gap-2 text-xs">
          {(Object.keys(BUCKET_META) as CollisionBucket[]).map((b) => {
            const meta = BUCKET_META[b];
            const Icon = meta.icon;
            const n = counts[b];
            if (n === 0) return null;
            return (
              <div key={b} className="flex items-center gap-1.5">
                <span
                  className="flex items-center gap-1 px-2 py-0.5 rounded-md font-mono uppercase tracking-wider text-[10px]"
                  style={{ color: meta.color, border: `1px solid ${meta.color}50` }}
                >
                  <Icon className="w-3 h-3" />
                  {meta.label} ({n})
                </span>
                <button
                  type="button"
                  onClick={() => applyToBucket(b, "replace")}
                  className="text-[var(--color-fg-dim)] hover:text-[var(--color-mint)] underline-offset-2 hover:underline"
                >
                  replace all
                </button>
                <span className="text-[var(--color-fg-muted)]">/</span>
                <button
                  type="button"
                  onClick={() => applyToBucket(b, "skip")}
                  className="text-[var(--color-fg-dim)] hover:text-[var(--color-coral)] underline-offset-2 hover:underline"
                >
                  skip all
                </button>
              </div>
            );
          })}
          <div className="flex items-center gap-2 ml-auto">
            <button
              type="button"
              onClick={() => applyToBucket("all", "replace")}
              className="text-[var(--color-fg-dim)] hover:text-[var(--color-fg)]"
            >
              Replace all
            </button>
            <span className="text-[var(--color-fg-muted)]">·</span>
            <button
              type="button"
              onClick={() => applyToBucket("all", "skip")}
              className="text-[var(--color-fg-dim)] hover:text-[var(--color-fg)]"
            >
              Skip all
            </button>
          </div>
        </div>

        <div className="flex-1 overflow-y-auto px-3 py-2 space-y-1">
          {items.map((it) => {
            const meta = BUCKET_META[it.bucket];
            const Icon = meta.icon;
            const decision = decisions[it.jobId];
            const incomingBigger = it.incomingWidth * it.incomingHeight > it.existingWidth * it.existingHeight;
            return (
              <div
                key={it.jobId}
                className="rounded-lg border border-[var(--color-glass-border)] bg-[var(--color-bg-1)]/40 px-3 py-2"
              >
                <div className="flex items-center gap-2 mb-1.5">
                  <span
                    className="flex items-center gap-1 px-1.5 py-0.5 rounded font-mono uppercase tracking-wider text-[9px]"
                    style={{ color: meta.color, border: `1px solid ${meta.color}50` }}
                  >
                    <Icon className="w-2.5 h-2.5" />
                    {meta.label}
                  </span>
                  {it.code && (
                    <span className="text-xs font-mono font-bold text-[var(--color-cyan)]">{it.code}</span>
                  )}
                  <div className="ml-auto flex items-center gap-1">
                    <button
                      type="button"
                      onClick={() => setDecisions((s) => ({ ...s, [it.jobId]: "replace" }))}
                      className={cn(
                        "flex items-center gap-1 px-2 py-1 rounded-md text-xs",
                        decision === "replace"
                          ? "bg-[var(--color-mint)]/20 text-[var(--color-mint)] ring-1 ring-[var(--color-mint)]/50"
                          : "text-[var(--color-fg-muted)] hover:text-[var(--color-fg)] hover:bg-[var(--color-glass)]",
                      )}
                    >
                      <Replace className="w-3 h-3" />
                      Replace
                    </button>
                    <button
                      type="button"
                      onClick={() => setDecisions((s) => ({ ...s, [it.jobId]: "skip" }))}
                      className={cn(
                        "flex items-center gap-1 px-2 py-1 rounded-md text-xs",
                        decision === "skip"
                          ? "bg-[var(--color-coral)]/20 text-[var(--color-coral)] ring-1 ring-[var(--color-coral)]/50"
                          : "text-[var(--color-fg-muted)] hover:text-[var(--color-fg)] hover:bg-[var(--color-glass)]",
                      )}
                    >
                      <SkipForward className="w-3 h-3" />
                      Skip
                    </button>
                  </div>
                </div>
                <div className="grid grid-cols-2 gap-3 text-xs">
                  <div className={cn("rounded-md p-2", !incomingBigger && "bg-[var(--color-mint)]/5")}>
                    <div className="text-[10px] uppercase tracking-wider font-mono text-[var(--color-fg-muted)] mb-1">Existing #{it.existingId}</div>
                    <div className="font-mono truncate text-[var(--color-fg-dim)]" title={it.existingFilename}>{it.existingFilename}</div>
                    <div className="text-[var(--color-fg-muted)] tabular-nums mt-0.5">
                      {it.existingWidth}×{it.existingHeight} · {fmtBytes(it.existingBytes)}
                    </div>
                  </div>
                  <div className={cn("rounded-md p-2", incomingBigger && "bg-[var(--color-mint)]/5")}>
                    <div className="text-[10px] uppercase tracking-wider font-mono text-[var(--color-fg-muted)] mb-1">Incoming</div>
                    <div className="font-mono truncate text-[var(--color-fg-dim)]" title={it.filename}>{it.filename}</div>
                    <div className="text-[var(--color-fg-muted)] tabular-nums mt-0.5">
                      {it.incomingWidth}×{it.incomingHeight} · {fmtBytes(it.incomingBytes)}
                    </div>
                  </div>
                </div>
              </div>
            );
          })}
        </div>

        <div className="px-5 py-3 border-t border-[var(--color-glass-border)] flex items-center justify-between">
          <div className="text-xs text-[var(--color-fg-muted)]">
            <span className="text-[var(--color-mint)]">{replaceCount} replace</span>
            {" · "}
            <span className="text-[var(--color-coral)]">{skipCount} skip</span>
            {" · "}
            replacements move the old file to <span className="font-mono">library/.superseded/</span>
          </div>
          <div className="flex items-center gap-2">
            <button
              type="button"
              onClick={onCancel}
              className="text-sm px-3 py-1.5 rounded-lg text-[var(--color-fg-dim)] hover:text-[var(--color-fg)] hover:bg-[var(--color-glass)]"
            >
              Cancel
            </button>
            <button
              type="button"
              onClick={() => onConfirm(decisions)}
              className="text-sm px-3 py-1.5 rounded-lg bg-[var(--color-cyan)]/20 text-[var(--color-cyan)] ring-1 ring-[var(--color-cyan)]/50 hover:bg-[var(--color-cyan)]/30"
            >
              Apply
            </button>
          </div>
        </div>
      </div>
    </div>,
    document.body,
  );
}
