"use client";

import React, {
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from "react";
import Link from "next/link";
import { usePathname } from "next/navigation";
import {
  AnimatePresence,
  motion,
  useAnimationControls,
  useReducedMotion,
  type PanInfo,
} from "framer-motion";
import confetti from "canvas-confetti";
import { Home, LayoutDashboard, RotateCcw } from "lucide-react";
import { useI18n } from "@/lib/i18n/context";
import {
  ErrorVariant,
  formatReceiptClock,
  getErrorCopy,
  shortRef,
} from "./errorCopy";

type ReceiptErrorPageProps = {
  variant: ErrorVariant;
  homeHref?: string;
  dashboardHref?: string;
  onRetry?: () => void;
};

type LedKey = "idle" | "scan" | "void" | "jam" | "ok";

const LED_COLOR: Record<LedKey, string> = {
  idle: "#94A3B8",
  scan: "#F59E0B",
  void: "#DC2626",
  jam: "#DC2626",
  ok: "#10B981",
};

const KONAMI_SEQUENCE = [
  "ArrowUp",
  "ArrowUp",
  "ArrowDown",
  "ArrowDown",
  "ArrowLeft",
  "ArrowRight",
  "ArrowLeft",
  "ArrowRight",
];

// --- deterministic pseudo-random (same output on server + client render) ---
function hashString(input: string): number {
  let h = 2166136261;
  for (let i = 0; i < input.length; i++) {
    h ^= input.charCodeAt(i);
    h = Math.imul(h, 16777619);
  }
  return h >>> 0;
}

function mulberry32(seed: number) {
  let a = seed;
  return function rand() {
    a |= 0;
    a = (a + 0x6d2b79f5) | 0;
    let t = Math.imul(a ^ (a >>> 15), 1 | a);
    t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
  };
}

function useToastQueue() {
  const [toasts, setToasts] = useState<{ id: number; text: string }[]>([]);
  const counter = useRef(0);
  const push = useCallback((text: string) => {
    const id = ++counter.current;
    setToasts((prev) => [...prev.slice(-2), { id, text }]);
    window.setTimeout(() => {
      setToasts((prev) => prev.filter((t) => t.id !== id));
    }, 3400);
  }, []);
  return { toasts, push };
}

function Barcode({ seed, className }: { seed: string; className?: string }) {
  const bars = useMemo(() => {
    const rand = mulberry32(hashString(`bar-${seed}`));
    const widths: number[] = [];
    let x = 0;
    while (x < 148) {
      const w = rand() > 0.72 ? 3 : rand() > 0.45 ? 2 : 1;
      widths.push(w);
      x += w + 2;
    }
    return widths;
  }, [seed]);

  return (
    <svg
      viewBox="0 0 150 38"
      className={className}
      role="img"
      aria-hidden="true"
    >
      {(() => {
        let x = 0;
        return bars.map((w, i) => {
          const rect = (
            <rect key={i} x={x} y={0} width={w} height={38} fill="#161C22" />
          );
          x += w + 2;
          return rect;
        });
      })()}
    </svg>
  );
}

function QrGlyph({ seed, className }: { seed: string; className?: string }) {
  const size = 9;
  const cells = useMemo(() => {
    const rand = mulberry32(hashString(`qr-${seed}`));
    const grid: boolean[][] = Array.from({ length: size }, () =>
      Array.from({ length: size }, () => rand() > 0.56),
    );
    const finder = (r0: number, c0: number) => {
      for (let r = 0; r < 3; r++) {
        for (let c = 0; c < 3; c++) {
          grid[r0 + r][c0 + c] = r === 1 && c === 1 ? false : true;
        }
      }
    };
    finder(0, 0);
    finder(0, size - 3);
    finder(size - 3, 0);
    return grid;
  }, [seed]);

  const cell = 100 / size;
  return (
    <svg
      viewBox="0 0 100 100"
      className={className}
      role="img"
      aria-hidden="true"
    >
      <rect x={0} y={0} width={100} height={100} fill="#FFFFFF" />
      {cells.map((row, r) =>
        row.map((on, c) =>
          on ? (
            <rect
              key={`${r}-${c}`}
              x={c * cell}
              y={r * cell}
              width={cell}
              height={cell}
              fill="#161C22"
            />
          ) : null,
        ),
      )}
    </svg>
  );
}

function tornEdgePath(seed: string, teeth = 14) {
  const rand = mulberry32(hashString(`torn-${seed}`));
  const points: string[] = ["0% 0%", "100% 0%", "100% 94%"];
  for (let i = teeth; i >= 0; i--) {
    const x = (i / teeth) * 100;
    const jitter = 3 + rand() * 3.5;
    const y = i % 2 === 0 ? 94 + jitter : 94;
    points.push(`${x.toFixed(2)}% ${y.toFixed(2)}%`);
  }
  return `polygon(${points.join(", ")})`;
}

export default function ReceiptErrorPage({
  variant,
  homeHref = "/",
  dashboardHref = "/dashboard",
  onRetry,
}: ReceiptErrorPageProps) {
  const { language } = useI18n();
  const lang = language === "de" ? "de" : "en";
  const copy = useMemo(() => getErrorCopy(variant, lang), [variant, lang]);
  const pathname = usePathname() || "/";
  const ref = shortRef(pathname);
  const reduceMotion = useReducedMotion();

  const [clock, setClock] = useState<string | null>(null);
  useEffect(() => {
    setClock(formatReceiptClock(lang));
  }, [lang]);

  const [setIndex, setSetIndex] = useState(0);
  const currentSet = copy.sets[setIndex % copy.sets.length];

  const [led, setLed] = useState<LedKey>("idle");
  const ledToken = useRef(0);
  const flashLed = useCallback((key: LedKey, ms = 1500) => {
    const token = ++ledToken.current;
    setLed(key);
    window.setTimeout(() => {
      if (ledToken.current === token) setLed("idle");
    }, ms);
  }, []);

  const [voided, setVoided] = useState(false);
  const [staffRevealed, setStaffRevealed] = useState(false);
  const [staffFirstReveal, setStaffFirstReveal] = useState(false);
  const [qrClicked, setQrClicked] = useState(false);
  const [printing, setPrinting] = useState(false);
  const reprintCount = useRef(0);

  const { toasts, push } = useToastQueue();

  const dropZoneRef = useRef<HTMLDivElement>(null);
  const paperControls = useAnimationControls();
  const [dropActive, setDropActive] = useState(false);

  useEffect(() => {
    paperControls.start({
      y: 0,
      opacity: 1,
      transition: { duration: reduceMotion ? 0.01 : 0.5, ease: [0.16, 1, 0.3, 1] },
    });
    // Entrance only — subsequent calls to paperControls (void/drag snap-back) are imperative.
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const handleReprint = useCallback(() => {
    setPrinting(true);
    flashLed("scan", 650);
    window.setTimeout(() => setPrinting(false), 420);
    setSetIndex((i) => (i + 1) % copy.sets.length);
    reprintCount.current += 1;
    if (reprintCount.current >= 3) {
      push(copy.persistToast);
      flashLed("jam", 1800);
    } else {
      push(copy.reprintToast);
    }
  }, [copy, flashLed, push]);

  const handleVoid = useCallback(() => {
    setVoided(true);
    flashLed("void", 2200);
    push(copy.voidToast);
  }, [copy, flashLed, push]);

  const handleQr = useCallback(() => {
    if (qrClicked) {
      push(copy.qrPersistToast);
    } else {
      setQrClicked(true);
      push(copy.qrToast);
    }
  }, [copy, push, qrClicked]);

  const handleStaffToggle = useCallback(() => {
    setStaffRevealed((v) => !v);
    if (!staffFirstReveal) {
      setStaffFirstReveal(true);
      push(copy.staffToast);
    }
  }, [copy, push, staffFirstReveal]);

  const handleDragEnd = useCallback(
    (_event: MouseEvent | TouchEvent | PointerEvent, info: PanInfo) => {
      const zone = dropZoneRef.current;
      paperControls.start({
        x: 0,
        y: 0,
        transition: { type: "spring", stiffness: 420, damping: 30 },
      });
      if (!zone) return;
      const rect = zone.getBoundingClientRect();
      const { x, y } = info.point;
      const hit =
        x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
      if (hit) {
        setDropActive(true);
        flashLed("ok", 1400);
        push(copy.excelToast);
        window.setTimeout(() => setDropActive(false), 900);
      }
    },
    [copy, paperControls, flashLed, push],
  );

  // Konami code + literal "404" digit easter eggs.
  const arrowBuffer = useRef<string[]>([]);
  const digitBuffer = useRef<string>("");
  useEffect(() => {
    function onKeyDown(e: KeyboardEvent) {
      if (e.key.startsWith("Arrow")) {
        arrowBuffer.current = [...arrowBuffer.current, e.key].slice(
          -KONAMI_SEQUENCE.length,
        );
        if (
          arrowBuffer.current.length === KONAMI_SEQUENCE.length &&
          arrowBuffer.current.every((k, i) => k === KONAMI_SEQUENCE[i])
        ) {
          arrowBuffer.current = [];
          push(copy.konamiToast);
          flashLed("ok", 2000);
          if (!reduceMotion) {
            confetti({
              particleCount: 70,
              spread: 68,
              startVelocity: 38,
              gravity: 1.1,
              origin: { y: 0.55 },
              colors: ["#161C22", "#94A3B8", "#F59E0B", "#FFFFFF"],
            });
          }
        }
      }
      if (/^[0-9]$/.test(e.key)) {
        digitBuffer.current = (digitBuffer.current + e.key).slice(-3);
        if (digitBuffer.current === "404") {
          digitBuffer.current = "";
          push(copy.digitToast);
          flashLed("scan", 1200);
        }
      }
    }
    window.addEventListener("keydown", onKeyDown);
    return () => window.removeEventListener("keydown", onKeyDown);
  }, [copy, flashLed, push, reduceMotion]);

  const tornPath = useMemo(
    () => tornEdgePath(`${variant}-${lang}-${setIndex}`),
    [variant, lang, setIndex],
  );

  const isErrorVariant = variant === "error";
  const ledRow: { key: LedKey; label: string }[] = [
    { key: "idle", label: copy.ledIdle },
    { key: "scan", label: copy.ledScan },
    { key: "void", label: copy.ledVoid },
    { key: "jam", label: copy.ledJam },
    { key: "ok", label: copy.ledOk },
  ];

  return (
    <div className="relative flex min-h-screen w-full flex-col items-center justify-center overflow-hidden bg-[#F6F9FF] px-6 py-14 font-sans text-[#161C22]">
      {/* For anyone reading the source instead of the page: */}
      <div
        aria-hidden="true"
        suppressHydrationWarning
        dangerouslySetInnerHTML={{ __html: `<!-- ${copy.sourceComment} -->` }}
      />

      <div className="flex w-full max-w-[380px] flex-col items-center">
        {/* Printer housing */}
        <div className="relative z-10 w-full rounded-[10px] bg-[#1C2127] px-4 pb-5 pt-3.5 shadow-[0_20px_45px_-16px_rgba(15,23,42,0.45)]">
          <div className="flex items-start justify-between">
            <div className="font-mono leading-none text-[#E2E8F0]">
              <div className="text-[13px] font-bold tracking-caps">
                {copy.brandMark}
              </div>
              <div className="mt-1 text-[9px] tracking-caps text-[#6B7280]">
                {copy.brandSub}
              </div>
            </div>
            <div className="flex flex-col items-end gap-1">
              <div className="flex items-center gap-2">
                {ledRow.map((l) => (
                  <span
                    key={l.key}
                    className="h-1.5 w-1.5 rounded-full transition-colors duration-300"
                    style={{
                      backgroundColor:
                        led === l.key ? LED_COLOR[l.key] : "#3A4048",
                      boxShadow:
                        led === l.key
                          ? `0 0 6px 1px ${LED_COLOR[l.key]}99`
                          : "none",
                    }}
                    title={l.label}
                  />
                ))}
              </div>
              <div className="font-mono text-[8px] tracking-caps text-[#6B7280]">
                {ledRow.find((l) => l.key === led)?.label}
              </div>
            </div>
          </div>

          <div className="relative mt-3 h-3 overflow-hidden rounded-full bg-black/70 shadow-[inset_0_2px_4px_rgba(0,0,0,0.6)]">
            <div className="absolute inset-x-3 top-[3px] h-px bg-white/10" />
          </div>
        </div>

        {/* Receipt paper */}
        <div className="relative w-[92%]">
          <motion.div
            drag
            animate={paperControls}
            dragElastic={0.22}
            dragMomentum={false}
            onDragEnd={handleDragEnd}
            whileDrag={{ scale: 1.03, boxShadow: "0 30px 50px -20px rgba(15,23,42,0.5)" }}
            initial={{ y: -14, opacity: 0 }}
            className="relative -mt-1 cursor-grab bg-white px-5 pb-8 pt-6 text-[#161C22] shadow-[0_16px_36px_-18px_rgba(15,23,42,0.35)] active:cursor-grabbing"
            style={{ clipPath: tornPath }}
          >
            <AnimatePresence>
              {voided && (
                <motion.div
                  key="void-stamp"
                  initial={{ opacity: 0, scale: 1.6, rotate: -18 }}
                  animate={{ opacity: 1, scale: 1, rotate: -12 }}
                  transition={{ type: "spring", stiffness: 260, damping: 14 }}
                  className="pointer-events-none absolute left-1/2 top-[38%] -translate-x-1/2 select-none border-[3px] border-[#DC2626] px-3 py-1 font-mono text-lg font-black tracking-caps text-[#DC2626]"
                  style={{ opacity: 0.82 }}
                >
                  {copy.ledVoid}
                </motion.div>
              )}
            </AnimatePresence>

            <motion.div
              animate={printing ? { opacity: [1, 0.4, 1] } : { opacity: 1 }}
              transition={{ duration: 0.4 }}
            >
              <div className="text-center">
                <div className="font-display text-lg font-extrabold tracking-tight">
                  {copy.brandMark}
                  <span className="text-[#94A3B8]">{copy.brandSub}</span>
                </div>
                <div className="mt-1.5 font-mono text-[10px] font-semibold tracking-caps text-[#B91C1C]">
                  {copy.codeLabel}
                </div>
              </div>

              <div className="my-4 border-t border-dashed border-[#CBD5E1]" />

              <h1 className="text-center font-display text-xl font-bold leading-snug text-[#161C22]">
                {copy.headline}
              </h1>
              <p className="mx-auto mt-2 max-w-[280px] text-center text-[12px] leading-relaxed text-[#475569]">
                {copy.body}
              </p>

              <div className="my-4 border-t border-dashed border-[#CBD5E1]" />

              <dl className="grid grid-cols-2 gap-y-1.5 font-mono text-[10px] text-[#475569]">
                <dt className="tracking-caps text-[#94A3B8]">{copy.txn}</dt>
                <dd className="text-right text-[#161C22]">{copy.txnValue}</dd>
                <dt className="tracking-caps text-[#94A3B8]">{copy.date}</dt>
                <dd className="text-right text-[#161C22]" suppressHydrationWarning>
                  {clock ?? "--.--.----  --:--"}
                </dd>
                <dt className="tracking-caps text-[#94A3B8]">{copy.ref}</dt>
                <dd className="truncate text-right text-[#161C22]" title={pathname}>
                  {ref}
                </dd>
                <dt className="tracking-caps text-[#94A3B8]">{copy.terminal}</dt>
                <dd className="text-right text-[#161C22]">{" "}</dd>
              </dl>

              <div className="my-4 border-t border-dashed border-[#CBD5E1]" />

              <div className="font-mono text-[11px]">
                <div className="mb-1.5 text-[10px] font-semibold tracking-caps text-[#161C22]">
                  {currentSet.title}
                </div>
                <AnimatePresence mode="wait">
                  <motion.ul
                    key={setIndex}
                    initial={{ opacity: 0, y: 6 }}
                    animate={{ opacity: 1, y: 0 }}
                    exit={{ opacity: 0, y: -6 }}
                    transition={{ duration: reduceMotion ? 0.01 : 0.22 }}
                    className="space-y-1"
                  >
                    {currentSet.lines.map((line, i) => (
                      <li key={i} className="flex justify-between gap-3 text-[#475569]">
                        <span className="truncate">{line.label}</span>
                        <span className="shrink-0 text-[#161C22]">{line.amount}</span>
                      </li>
                    ))}
                  </motion.ul>
                </AnimatePresence>
                <div className="mt-2 flex justify-between border-t border-[#E2E8F0] pt-1.5 text-[#475569]">
                  <span>SUBTOTAL</span>
                  <span>{currentSet.subtotal}</span>
                </div>
                <div className="mt-1 flex justify-between text-sm font-bold text-[#161C22]">
                  <span>TOTAL</span>
                  <span>{currentSet.total}</span>
                </div>
              </div>

              <div className="my-4 border-t border-dashed border-[#CBD5E1]" />

              <div className="text-center font-mono text-[10px] font-semibold tracking-caps text-[#161C22]">
                {currentSet.status}
              </div>
              <p className="mt-1 text-center text-[11px] text-[#475569]">
                {currentSet.footer}
              </p>
              <p className="text-center font-mono text-[9px] tracking-caps text-[#94A3B8]">
                {currentSet.note}
              </p>

              <div className="my-4 border-t border-dashed border-[#CBD5E1]" />

              <div className="flex items-end justify-between gap-4">
                <button
                  type="button"
                  onClick={handleReprint}
                  aria-label={copy.barcodeLabel}
                  className="group flex flex-col items-center gap-1 transition-transform duration-150 hover:-translate-y-0.5 focus-visible:-translate-y-0.5"
                >
                  <Barcode seed={`${variant}-${lang}`} className="h-9 w-[150px]" />
                  <span className="font-mono text-[8px] tracking-caps text-[#94A3B8] group-hover:text-[#161C22]">
                    {copy.barcodeLabel}
                  </span>
                </button>

                <button
                  type="button"
                  onClick={handleQr}
                  aria-label="QR"
                  className="shrink-0 rounded-[2px] p-0.5 ring-1 ring-[#E2E8F0] transition-transform duration-150 hover:-translate-y-0.5 hover:ring-[#161C22] focus-visible:-translate-y-0.5"
                >
                  <QrGlyph seed={`${variant}-${lang}-${qrClicked}`} className="h-11 w-11" />
                </button>
              </div>

              <div className="mt-4 flex justify-center">
                <button
                  type="button"
                  onClick={handleVoid}
                  aria-label={copy.ledVoid}
                  className="rounded-sm border border-[#DC2626]/50 px-2.5 py-1 font-mono text-[9px] font-semibold tracking-caps text-[#DC2626]/70 transition-colors hover:border-[#DC2626] hover:text-[#DC2626]"
                >
                  {copy.ledVoid}
                </button>
              </div>
            </motion.div>
          </motion.div>

          {/* Staff copy peel */}
          <div className="relative -mt-px flex justify-center">
            <button
              type="button"
              onClick={handleStaffToggle}
              aria-expanded={staffRevealed}
              className="z-10 rounded-b-sm bg-[#EEF2F7] px-3 py-1 font-mono text-[8px] tracking-caps text-[#94A3B8] shadow-[0_4px_10px_-6px_rgba(15,23,42,0.3)] transition-colors hover:text-[#161C22]"
            >
              {staffRevealed ? "▴" : "▾"} {copy.staffCopy}
            </button>
          </div>
          <AnimatePresence>
            {staffRevealed && (
              <motion.div
                key="staff-copy"
                initial={{ opacity: 0, height: 0, y: -6 }}
                animate={{ opacity: 1, height: "auto", y: 0 }}
                exit={{ opacity: 0, height: 0, y: -6 }}
                transition={{ duration: reduceMotion ? 0.01 : 0.28 }}
                className="mx-auto -mt-1 w-[92%] overflow-hidden bg-[#FAFBFD] px-5 py-3 text-center shadow-[0_10px_24px_-16px_rgba(15,23,42,0.3)]"
              >
                <div className="font-mono text-[9px] font-semibold tracking-caps text-[#94A3B8]">
                  {copy.staffCopy}
                </div>
                <div className="mt-1 font-mono text-[10px] text-[#161C22]">
                  {currentSet.status} · {currentSet.total}
                </div>
              </motion.div>
            )}
          </AnimatePresence>
        </div>

        {/* Actions */}
        <div className="mt-8 flex flex-wrap items-center justify-center gap-3">
          {isErrorVariant ? (
            <button
              type="button"
              onClick={() => onRetry?.()}
              className="zenith-btn-primary inline-flex items-center gap-2 px-5 py-2.5"
            >
              <RotateCcw className="h-3.5 w-3.5" />
              <span>{copy.primary}</span>
            </button>
          ) : (
            <Link
              href={homeHref}
              className="zenith-btn-primary inline-flex items-center gap-2 px-5 py-2.5"
            >
              <Home className="h-3.5 w-3.5" />
              <span>{copy.primary}</span>
            </Link>
          )}
          <Link
            href={isErrorVariant ? homeHref : dashboardHref}
            className="zenith-btn-secondary inline-flex items-center gap-2 px-5 py-2.5"
          >
            {isErrorVariant ? (
              <Home className="h-3.5 w-3.5" />
            ) : (
              <LayoutDashboard className="h-3.5 w-3.5" />
            )}
            <span>{copy.secondary}</span>
          </Link>
        </div>

        {/* Drag target */}
        <div
          ref={dropZoneRef}
          className={`mt-10 flex flex-col items-center gap-1.5 rounded-sm border border-dashed px-4 py-3 font-mono text-[9px] tracking-caps transition-colors duration-300 ${
            dropActive
              ? "border-[#10B981] text-[#10B981]"
              : "border-[#CBD5E1] text-[#94A3B8]"
          }`}
        >
          <svg width="20" height="16" viewBox="0 0 20 16" aria-hidden="true">
            <rect x="0.5" y="0.5" width="19" height="15" fill="none" stroke="currentColor" />
            <line x1="0.5" y1="6" x2="19.5" y2="6" stroke="currentColor" />
            <line x1="0.5" y1="11" x2="19.5" y2="11" stroke="currentColor" />
            <line x1="7" y1="0.5" x2="7" y2="15.5" stroke="currentColor" />
            <line x1="13.5" y1="0.5" x2="13.5" y2="15.5" stroke="currentColor" />
          </svg>
          {copy.excelSheet}
        </div>
      </div>

      {/* Toasts */}
      <div className="pointer-events-none fixed inset-x-0 bottom-5 z-50 flex flex-col items-center gap-2 px-6">
        <AnimatePresence>
          {toasts.map((t) => (
            <motion.div
              key={t.id}
              initial={{ opacity: 0, y: 14, scale: 0.95 }}
              animate={{ opacity: 1, y: 0, scale: 1 }}
              exit={{ opacity: 0, y: 8, scale: 0.97 }}
              transition={{ duration: reduceMotion ? 0.01 : 0.25 }}
              className="max-w-[320px] border border-[#161C22] bg-white px-3.5 py-2 text-center font-mono text-[11px] leading-snug text-[#161C22] shadow-[0_10px_24px_-12px_rgba(15,23,42,0.4)]"
            >
              {t.text}
            </motion.div>
          ))}
        </AnimatePresence>
      </div>
    </div>
  );
}
