"use client";

import { useCallback, useEffect, useMemo, useState } from "react";
import { Sparkles, X, Zap } from "lucide-react";
import { useTranslation } from "react-i18next";

import { getDrawResultByNo } from "@/api/draw";
import { Button } from "@/components/ui/button";
import { formatMinorAsCurrency } from "@/lib/money";
import { playerViewportOverlayClass } from "@/lib/player-viewport";
import { cn } from "@/lib/utils";

export type JackpotBurstEvent = {
  draw_id: number;
  draw_no: string;
  first_prize_number: string;
  currency_code: string;
  total_payout_amount: number;
  winner_count: number;
  trigger_type: string;
  pool_amount_after: number;
  emitted_at_ms?: number;
};

type JackpotBurstOverlayProps = {
  event: JackpotBurstEvent | null;
  onClose: () => void;
};

const PARTICLE_SEEDS = [
  { left: "8%", delay: "0s", duration: "2.2s", size: 4 },
  { left: "22%", delay: "0.4s", duration: "2.6s", size: 3 },
  { left: "38%", delay: "0.1s", duration: "2.4s", size: 5 },
  { left: "55%", delay: "0.7s", duration: "2.8s", size: 3 },
  { left: "72%", delay: "0.2s", duration: "2.3s", size: 4 },
  { left: "88%", delay: "0.5s", duration: "2.5s", size: 3 },
  { left: "15%", delay: "0.9s", duration: "2.7s", size: 3 },
  { left: "65%", delay: "0.35s", duration: "2.1s", size: 4 },
] as const;

const ROLL_STAGGER_MS = 380;
const ROLL_BASE_MS = 900;
const ROLL_TICK_MS = 55;

function isMissingPrizeNumber(raw: string): boolean {
  const cleaned = raw.replace(/\s/g, "");
  return !cleaned || /^-+$/.test(cleaned);
}

function normalizePrizeDigits(raw: string): string[] {
  const cleaned = raw.replace(/\s/g, "");
  if (isMissingPrizeNumber(raw)) {
    return ["—", "—", "—", "—"];
  }
  const padded = cleaned.padStart(4, "0").slice(-4);
  return padded.split("");
}

function useRollingDigits(finalNumber: string) {
  const targets = useMemo(() => normalizePrizeDigits(finalNumber), [finalNumber]);
  const [display, setDisplay] = useState<string[]>(() => ["?", "?", "?", "?"]);
  const [allRevealed, setAllRevealed] = useState(false);
  const [poppedIndex, setPoppedIndex] = useState<number | null>(null);

  useEffect(() => {
    const intervals: ReturnType<typeof setInterval>[] = [];
    const timeouts: ReturnType<typeof setTimeout>[] = [];

    targets.forEach((target, index) => {
      const tick = setInterval(() => {
        setDisplay((prev) => {
          const next = [...prev];
          if (target === "—") {
            next[index] = "—";
          } else {
            next[index] = String(Math.floor(Math.random() * 10));
          }
          return next;
        });
      }, ROLL_TICK_MS);
      intervals.push(tick);

      const stopAt = ROLL_BASE_MS + index * ROLL_STAGGER_MS;
      const stop = setTimeout(() => {
        clearInterval(tick);
        setDisplay((prev) => {
          const next = [...prev];
          next[index] = target;
          return next;
        });
        setPoppedIndex(index);
        const clearPop = setTimeout(() => setPoppedIndex(null), 320);
        timeouts.push(clearPop);

        if (index === targets.length - 1) {
          const revealDone = setTimeout(() => setAllRevealed(true), 200);
          timeouts.push(revealDone);
        }
      }, stopAt);
      timeouts.push(stop);
    });

    return () => {
      intervals.forEach(clearInterval);
      timeouts.forEach(clearTimeout);
    };
  }, [targets]);

  return { display, allRevealed, poppedIndex };
}

function BurstParticles() {
  return (
    <div className="pointer-events-none absolute inset-0 overflow-hidden" aria-hidden>
      {PARTICLE_SEEDS.map((p, i) => (
        <span
          key={i}
          className="absolute bottom-[18%] rounded-full bg-[#e8b84a] opacity-80"
          style={{
            left: p.left,
            width: p.size,
            height: p.size,
            animation: `jackpot-particle ${p.duration} ease-out ${p.delay} infinite`,
          }}
        />
      ))}
    </div>
  );
}

function RollingDigit({
  char,
  popping,
}: {
  char: string;
  popping: boolean;
}) {
  return (
    <span
      className={cn(
        "inline-flex min-w-[2.1rem] items-center justify-center rounded-lg border border-[#e8c96a] bg-gradient-to-b from-[#fff9e8] to-[#fff3d4] px-1 py-1 font-mono text-[2rem] font-black leading-none text-[#b8860b] shadow-[inset_0_1px_0_rgba(255,255,255,0.9),0_2px_8px_rgba(201,162,39,0.12)]",
        popping && "animate-[jackpot-digit-pop_0.32s_ease-out]",
      )}
    >
      {char}
    </span>
  );
}

export function JackpotBurstOverlay({ event, onClose }: JackpotBurstOverlayProps) {
  if (!event) return null;
  return (
    <JackpotBurstOverlayContent
      key={`${event.draw_id}-${event.emitted_at_ms ?? 0}`}
      event={event}
      onClose={onClose}
    />
  );
}

function useResolvedFirstPrizeNumber(event: JackpotBurstEvent) {
  const fromEvent = event.first_prize_number;
  const eventHasNumber = !isMissingPrizeNumber(fromEvent);
  const [fetchedNumber, setFetchedNumber] = useState<string | null>(null);
  const [fetchDone, setFetchDone] = useState(eventHasNumber);

  useEffect(() => {
    if (eventHasNumber) return;

    let cancelled = false;

    void getDrawResultByNo(event.draw_no)
      .then((detail) => {
        if (cancelled) return;
        const first = detail.results?.["1st"]?.trim() ?? "";
        if (!isMissingPrizeNumber(first)) {
          setFetchedNumber(first);
        }
      })
      .finally(() => {
        if (!cancelled) setFetchDone(true);
      });

    return () => {
      cancelled = true;
    };
  }, [event.draw_no, eventHasNumber]);

  const number = eventHasNumber ? fromEvent : (fetchedNumber ?? fromEvent);
  const pending = !eventHasNumber && (!fetchDone || isMissingPrizeNumber(number));

  return { number, pending };
}

function JackpotBurstOverlayContent({
  event,
  onClose,
}: {
  event: JackpotBurstEvent;
  onClose: () => void;
}) {
  const { t } = useTranslation("player");
  const { number: prizeNumber, pending: prizePending } = useResolvedFirstPrizeNumber(event);
  const { display, allRevealed, poppedIndex } = useRollingDigits(prizeNumber);

  const handleKeyDown = useCallback(
    (e: React.KeyboardEvent) => {
      if (e.key === "Escape") onClose();
    },
    [onClose],
  );

  const currency = event.currency_code.toUpperCase();
  const amount = formatMinorAsCurrency(event.total_payout_amount, currency);

  return (
    <div
      className={cn(
        playerViewportOverlayClass,
        "z-[90] flex items-center justify-center bg-white/88 px-4 py-6 text-slate-900 backdrop-blur-[2px] animate-[jackpot-backdrop-in_0.35s_ease-out]",
      )}
      style={{
        backgroundImage:
          "radial-gradient(ellipse 75% 55% at 50% 38%, rgba(245,197,66,0.14) 0%, transparent 60%)",
      }}
      role="dialog"
      aria-modal="true"
      aria-label={t("hall.jackpotBurst.title")}
      onKeyDown={handleKeyDown}
    >
      <div
        className="pointer-events-none absolute inset-0 animate-[jackpot-flash_0.55s_ease-out_forwards] bg-[radial-gradient(circle_at_50%_42%,rgba(255,236,180,0.55)_0%,transparent_58%)]"
        aria-hidden
      />

      <BurstParticles />

      <div
        className="pointer-events-none absolute left-1/2 top-[28%] size-64 -translate-x-1/2 rounded-full border border-[#e8c96a]/35 animate-[jackpot-ring-pulse_1.8s_ease-out_infinite]"
        aria-hidden
      />
      <div
        className="pointer-events-none absolute left-1/2 top-[28%] size-64 -translate-x-1/2 rounded-full border border-[#e8c96a]/20 animate-[jackpot-ring-pulse_1.8s_ease-out_0.6s_infinite]"
        aria-hidden
      />

      <div className="relative w-full max-w-[420px] animate-[jackpot-card-in_0.65s_cubic-bezier(0.22,1,0.36,1)]">
        <div className="absolute -inset-[1px] overflow-hidden rounded-2xl">
          <div
            className="absolute inset-[-50%] bg-[conic-gradient(from_0deg,#e8c96a,#f5d88a,#c9a227,#e8c96a)] opacity-90 animate-[jackpot-border-spin_4s_linear_infinite]"
            aria-hidden
          />
        </div>

        <div className="relative flex flex-col items-center rounded-2xl border border-[#f0e4c4] bg-white px-5 py-6 text-center shadow-[0_20px_50px_rgba(15,23,42,0.12),0_0_0_1px_rgba(245,197,66,0.08)]">
          <Button
            type="button"
            variant="ghost"
            size="icon"
            className="absolute right-2 top-2 z-10 text-slate-500 hover:bg-slate-100 hover:text-slate-800"
            onClick={onClose}
            aria-label={t("hall.jackpotBurst.close")}
          >
            <X className="size-4" aria-hidden />
          </Button>

          <div className="relative mb-3">
            <div
              className="absolute inset-0 rounded-full bg-[#f5c542]/25 blur-xl"
              aria-hidden
            />
            <div className="relative flex size-16 items-center justify-center rounded-full border-2 border-[#e8c96a] bg-gradient-to-br from-[#fff9e8] to-[#fff3d4] shadow-[0_4px_20px_rgba(201,162,39,0.22)]">
              <Zap
                className="size-8 text-[#c9a227] animate-[jackpot-lightning_1.4s_ease-in-out_infinite]"
                aria-hidden
              />
            </div>
            <Sparkles
              className="absolute -right-1 -top-1 size-4 text-[#d4a82a]"
              aria-hidden
            />
          </div>

          <h2 className="bg-gradient-to-r from-[#9a7b1a] via-[#c9a227] to-[#d4a82a] bg-[length:200%_auto] bg-clip-text text-lg font-black uppercase tracking-[0.14em] text-transparent animate-[jackpot-shimmer_2.8s_linear_infinite]">
            {t("hall.jackpotBurst.title")}
          </h2>
          <p className="mt-2 max-w-[320px] text-sm font-medium text-slate-600">
            {t("hall.jackpotBurst.subtitle", { drawNo: event.draw_no })}
          </p>

          <div className="relative my-5 w-full overflow-hidden rounded-xl border border-[#f0e4c4] bg-[#faf8f3] px-3 py-5 shadow-[inset_0_1px_0_rgba(255,255,255,0.9)]">
            <div
              className="pointer-events-none absolute inset-x-0 top-0 h-px bg-gradient-to-r from-transparent via-[#e8c96a]/70 to-transparent"
              aria-hidden
            />
            <div className="flex items-center justify-center gap-2">
              {display.map((char, i) => (
                <RollingDigit key={i} char={char} popping={poppedIndex === i} />
              ))}
            </div>
            <p className="mt-3 text-xs font-semibold uppercase tracking-wider text-slate-500">
              {t("hall.jackpotBurst.number")}
            </p>
            {prizePending && isMissingPrizeNumber(prizeNumber) ? (
              <p className="mt-1 text-xs text-amber-700/90">
                {t("hall.jackpotBurst.numberPending")}
              </p>
            ) : null}
          </div>

          <div className="w-full space-y-2 text-left text-sm">
            <div
              className={cn(
                "flex items-center justify-between gap-3 rounded-lg border border-[#f0e4c4] bg-gradient-to-r from-[#fff9e8] to-[#fffcf5] px-3 py-2.5",
                allRevealed &&
                  "animate-[jackpot-amount-row-glow_2s_ease-in-out_infinite]",
              )}
            >
              <span className="text-slate-600">{t("hall.jackpotBurst.amount")}</span>
              <span
                className={cn(
                  "text-right text-base font-black text-[#b8860b]",
                  allRevealed && "animate-[jackpot-amount-glow_2s_ease-in-out_infinite]",
                )}
              >
                {amount}
              </span>
            </div>
            <div className="flex items-center justify-between gap-3 rounded-lg border border-[#e8edf4] bg-[#f8fafc] px-3 py-2.5">
              <span className="text-slate-500">{t("hall.jackpotBurst.winners")}</span>
              <span className="font-bold tabular-nums text-slate-900">
                {event.winner_count}
              </span>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

