"use client";

import { useEffect, useMemo, useRef, useState } from "react";
import { getFreeSpin, getSpinSub } from "@/app/lib/api/spin";
import { User } from "@/constants/types";
import { useSelector } from "react-redux";
import { CardTrack } from "./CardTrack";
import { CardColumns } from "./CardColumns";
import BoxLayout from "./BoxLayout";
import AlertModal from "../ui/AlertModal";
import { useAppDispatch } from "@/app/lib/hooks";
import { updateUser } from "@/app/store/authSlice";
import { updateSession } from "@/app/lib/api/inventory";
import WhatsInsideTheBoxGrid from "./WhatsInsideTheBoxGrid";

type ExtendedCard = Card & { _i: number };

type Card = {
  id: number;
  image: string;
  name: string;
  price?: number;
  type?: string;
};

type BoxItem = {
  id: number;
  name: string;
  price: string;
  image: string;
};

type PokemonBoxSpinnerProps = {
  boltMode: boolean;
  boxId: string | null;
  selectedMode: number; // ✅ NEW
  setSelectedMode: (n: number) => void; // ✅ NEW
  box?: BoxItem;
};

export default function PokemonBoxSpinner({
  boltMode,
  boxId,
  selectedMode,
  setSelectedMode,
  box,
}: PokemonBoxSpinnerProps) {
  const [spinning, setSpinning] = useState(false);
  const [modalOpen, setModalOpen] = useState(false);
  const [modalType, setModalType] = useState<"success" | "error">("success");
  const [modalMsg, setModalMsg] = useState("");

  const [winners, setWinners] = useState<Card[]>([]);
  const [targetIndices, setTargetIndices] = useState<number[]>([]);
  const [winnerTrackByCol, setWinnerTrackByCol] = useState<number[]>([]);

  const lockedMode = useMemo(() => {
    const n = Number(boxId);
    if (!boxId || !Number.isFinite(n)) return null;
    return Math.min(6, Math.max(1, n));
  }, [boxId]);

  const autoSpinRanRef = useRef(false);

  useEffect(() => {
    if (!lockedMode) return;

    if (autoSpinRanRef.current) return;

    if (cardsLoading) return;

    if (spinning) return;

    if (!user) return;

    // ✅ mode set
    setSelectedMode(lockedMode);

    requestAnimationFrame(() => {
      if (autoSpinRanRef.current) return;
      autoSpinRanRef.current = true;
      // handleFreeSpin(lockedMode); // ✅ auto click free spin
    });
  }, [lockedMode, spinning]);

  const [phase, setPhase] = useState<
    | "idle"
    | "accelerating"
    | "fast"
    | "slow"
    | "slower"
    | "slowest"
    | "stopping"
    | "showWinners"
  >("idle");

  const [offset, setOffset] = useState(0);
  const [columnOffsets, setColumnOffsets] = useState<number[]>([]);
  const [backendRawValues, setBackendRawValues] = useState<string[]>([]);

  const [cards, setCards] = useState<Card[]>([]);

  const CARD_W = 128;
  const GAP = 16;
  const ITEM_W = CARD_W + GAP;
  const viewportRef = useRef<HTMLDivElement | null>(null);
  const trackRef = useRef<HTMLDivElement | null>(null);
  const cardRefs = useRef<(HTMLDivElement | null)[]>([]);
  const columnRefs = useRef<(HTMLDivElement | null)[]>([]);
  const [centerIndices, setCenterIndices] = useState<number[]>([]);
  const [centerIndex, setCenterIndex] = useState<number | null>(null);
  const [cardsLoading, setCardsLoading] = useState(true);
  const [cardsError, setCardsError] = useState<string | null>(null);
  const [frozenY, setFrozenY] = useState<number[]>([]);
  const [spinValues, setSpinValues] = useState<number[]>([]);
  const [stopAligned, setStopAligned] = useState(false);

  const STOP_TRANSITION_MS = 1000;
  const [winnerIdByCol, setWinnerIdByCol] = useState<number[]>([]); // per column winner card id
  const user = useSelector((state: any) => state.auth.user) as User | null;
  const didRunRef = useRef(false);
  const spinValuesRef = useRef<number[] | null>(null);
  const listRefs = useRef<(HTMLDivElement | null)[]>([]);

  const dispatch = useAppDispatch();

  const track: ExtendedCard[] = useMemo(() => {
    const repeats = selectedMode === 1 ? 8 : 16;

    return Array.from({ length: repeats })
      .flatMap(() => cards)
      .map((c, i) => ({ ...c, _i: i }));
  }, [selectedMode, cards]); // ✅ cards dependency add

  // track should be ExtendedCard[]
  const extendedTrack: ExtendedCard[] = useMemo(
    () =>
      track.map((c, i) => ({
        ...c,
        _i: i,
      })),
    [track],
  );

  const columns = useMemo(() => {
    if (selectedMode === 1) return [] as ExtendedCard[][];
    const numCols = selectedMode;

    const rotate = <T,>(arr: T[], offset: number) => {
      const len = arr.length;
      if (!len) return arr;
      const shift = ((offset % len) + len) % len;
      return [...arr.slice(shift), ...arr.slice(0, shift)];
    };

    return Array.from({ length: numCols }, (_, colIdx) => {
      // different start for each column
      const offset = colIdx * 2; // change 2 -> 3/5 for more variation
      return rotate(extendedTrack, offset).map((c, i) => ({ ...c, _i: i }));
    });
  }, [selectedMode, extendedTrack]);

  // const segWidth = cards.length * ITEM_W;
  const segWidth = (cards.length || 1) * ITEM_W;

  useEffect(() => {
    setColumnOffsets(new Array(columns.length).fill(0));
  }, [columns.length]);

  useEffect(() => {
    if (phase === "idle" || phase === "showWinners") return;

    const check = () => {
      const vp = viewportRef.current;
      if (!vp) return;

      const vpRect = vp.getBoundingClientRect();
      const centerX = vpRect.left + vpRect.width / 2;

      let closest = null;
      let minDist = Infinity;

      cardRefs.current.forEach((el, i) => {
        if (!el) return;
        const rect = el.getBoundingClientRect();
        const cardCenter = rect.left + rect.width / 2;

        const dist = Math.abs(centerX - cardCenter);
        if (dist < minDist) {
          minDist = dist;
          closest = i;
        }
      });

      setCenterIndex(closest);
      requestAnimationFrame(check);
    };

    requestAnimationFrame(check);
  }, [phase]);

  const freeSubSpin = async (mode: number) => {
    if (!user) return;

    try {
      const res = await getSpinSub(user.token, user.userId, mode);
      if (res.resp === "error") {
        setModalType("error"); // or "login" if you have a custom type
        setModalMsg(res.msg);
        setModalOpen(true);
        return;
      }
      if (res.resp === "success") {
        dispatch(updateUser({ coins: res?.coins, gems: res?.gems }));
        await updateSession({ coins: res?.coins, gems: res?.gems });
      }

      setBackendRawValues(res?.values || []);
      const vals = (res?.values || []).map((v: string) => Number(v) - 1);

      spinValuesRef.current = vals; // ✅ store immediately
      setSpinValues(vals); // debug

      // ✅ also store winner card id per column
      if (selectedMode > 1) {
        setWinnerIdByCol(
          Array.from(
            { length: selectedMode },
            (_, i) => cards[vals[i]]?.id ?? -1,
          ),
        );
      }
      return vals;
    } catch (e: any) {
      spinValuesRef.current = null;

      setWinnerIdByCol([]);

      throw e;
    }
  };

  const freeSpin = async () => {
    try {
      setCardsLoading(true);
      setCardsError(null);
      setSpinning(true);
      const response = await getFreeSpin();

      // ✅ API se cards set
      const apiCards = (response?.data || []).map((x: any) => ({
        id: Number(x.id),
        name: x.name,
        image: x.image, // example: "/images/packs/Chilling-Reign.png"
        price: x.price != null ? Number(x.price) : undefined, // ✅ add this
      })) as Card[];

      setCards(apiCards);
    } catch (error: any) {
      console.error(error);
      setCardsError(error?.message || "Failed to load cards");
    } finally {
      setSpinning(false);
      setCardsLoading(false);
    }
  };

  useEffect(() => {
    if (didRunRef.current) return;
    didRunRef.current = true;

    freeSpin();
  }, []);

  const baseIndexById = useMemo(() => {
    const m = new Map<number, number>();
    cards.forEach((c, idx) => m.set(c.id, idx)); // 0-based
    return m;
  }, [cards]);

  const handleFreeSpin = async (modeArg?: number) => {
    // there was selectedMode before this mode
    const mode = typeof modeArg === "number" ? modeArg : selectedMode;

    if (!user) {
      setModalType("error"); // or "login" if you have a custom type
      setModalMsg("Please log in to continue.");
      setModalOpen(true);
      return;
    }

    if (spinning) return;
    // setSpinning(true);

    let vals: number[]; // or whatever type you expect
    try {
      const data = await freeSubSpin(mode);
      // If your API returns vals directly, adjust this line:
      vals = data.vals ?? data;
    } catch (err: any) {
      // setModalType("error");
      // setModalMsg(err?.message || "You can not play game.");
      // setModalOpen(true);
      console.log("err", err.message);
      return; // ✅ STOP HERE, don’t run spin
    }
    setWinnerTrackByCol(mode === 1 ? [] : new Array(mode).fill(-1));
    setStopAligned(false);

    // const vals = await freeSubSpin();
    // console.log("vals", vals);

    const accelTime = boltMode ? 200 : 800;
    const fastTime = boltMode ? 200 : 1000;
    const slowTime = boltMode ? 200 : 2000;
    const slowerTime = boltMode ? 200 : 2000;
    const slowestTime = boltMode ? 200 : 2000;
    // const beforeRevealDelay = boltMode ? 400 : 1600;
    const beforeRevealDelayBase = boltMode ? 400 : 1600;

    // ✅ Mode 2–6 me reveal hamesha stop animation ke baad ho
    const beforeRevealDelay =
      selectedMode === 1
        ? beforeRevealDelayBase
        : Math.max(beforeRevealDelayBase, STOP_TRANSITION_MS + 50);

    const afterRevealDelay = boltMode ? 1200 : 1000;

    const TOTAL_FALLBACK_MS =
      accelTime +
      fastTime +
      slowTime +
      slowerTime +
      slowestTime +
      STOP_TRANSITION_MS +
      2000;

    const safetyTimeout = setTimeout(() => {
      setPhase("showWinners");
      setSpinning(false);
    }, TOTAL_FALLBACK_MS);

    setSpinning(true);
    setPhase("accelerating");
    setWinners([]);
    setTargetIndices([]);
    setOffset(0);
    // ❌ setColumnOffsets([]);

    // ✅ keep correct length immediately:
    setColumnOffsets(mode === 1 ? [] : new Array(mode).fill(0));
    setCenterIndices(mode === 1 ? [] : new Array(mode).fill(-1));
    setFrozenY(mode === 1 ? [] : new Array(mode).fill(0));

    // 1) ACCELERATE → FAST
    setTimeout(() => {
      setPhase("fast");

      // 2) FAST → SLOW
      setTimeout(() => {
        setPhase("slow");

        // 3) SLOW → SLOWER
        setTimeout(() => {
          setPhase("slower");

          // 4) SLOWER → SLOWEST
          setTimeout(() => {
            setPhase("slowest");

            // 5) SLOWEST → STOP
            setTimeout(() => {
              setPhase("stopping");

              // =========================
              // MODE 1 (HORIZONTAL)
              // =========================
              if (selectedMode === 1) {
                // const picked = cards[Math.floor(Math.random() * cards.length)];
                const baseIdx =
                  vals[0] ?? Math.floor(Math.random() * cards.length);
                const picked = cards[baseIdx];
                const pickedWinners: Card[] = [picked];
                setWinners(pickedWinners);

                const vp = viewportRef.current;
                if (!vp || !trackRef.current) return;

                const vpCenter = (vp.clientWidth || 0) / 2;

                let currentX = 0;
                try {
                  const style = getComputedStyle(trackRef.current);
                  const t = style.transform;
                  if (t && t !== "none") {
                    const m = new DOMMatrix(t);
                    currentX = m.m41;
                  }
                } catch {}

                const progressInSeg =
                  ((-currentX % segWidth) + segWidth) % segWidth;

                let nearestIndex = 0;
                let nearestDist = Number.POSITIVE_INFINITY;

                track.forEach((c, i) => {
                  // if (c.name !== pickedWinners[0].name) return;
                  if (c.id !== picked.id) return;

                  const centerX =
                    ((i * ITEM_W + CARD_W / 2) % segWidth) +
                    Math.floor((i * ITEM_W) / segWidth) * segWidth;

                  const viewCenterPos = progressInSeg + vpCenter;
                  const d = Math.abs(centerX - viewCenterPos);

                  if (d < nearestDist) {
                    nearestDist = d;
                    nearestIndex = i;
                  }
                });

                setTargetIndices([nearestIndex]);

                const finalCenter = nearestIndex * ITEM_W + CARD_W / 2;
                const finalTranslate = -(finalCenter - vpCenter);
                setOffset(finalTranslate);
              } else {
                // =========================
                // MODES 2–6 (VERTICAL)
                // =========================
                const freezeNow = (numCols: number) => {
                  const frozen = new Array(numCols).fill(0);

                  for (let colIdx = 0; colIdx < numCols; colIdx++) {
                    const el = listRefs.current[colIdx];
                    if (!el) continue;

                    const t = getComputedStyle(el).transform;
                    if (t && t !== "none") {
                      const m = new DOMMatrix(t);
                      frozen[colIdx] = m.m42; // translateY
                    }
                  }

                  setFrozenY(frozen);
                  return frozen;
                };

                const numCols = selectedMode;

                // ✅ 1) freeze current animation translateY BEFORE stopping
                const frozen = freezeNow(numCols);

                // ✅ 2) now switch to stopping (list will render using frozenY)
                setPhase("stopping");

                // ✅ 3) offsets compute AFTER freeze applied
                requestAnimationFrame(() => {
                  requestAnimationFrame(() => {
                    const cols = columns; // ✅ use rendered columns

                    const pickedWinners: Card[] = new Array(numCols);
                    const winnerTrackIndices: number[] = new Array(
                      numCols,
                    ).fill(-1);
                    const newOffsets: number[] = new Array(numCols).fill(0);

                    cols.forEach((colCards, colIdx) => {
                      const colEl = columnRefs.current[colIdx];
                      const listEl = listRefs.current[colIdx];
                      if (!colEl || !listEl || !colCards.length) return;

                      const baseIdx0 =
                        vals[colIdx] ??
                        Math.floor(Math.random() * cards.length);
                      const desiredBaseCard = cards[baseIdx0];
                      if (!desiredBaseCard) return;

                      pickedWinners[colIdx] = desiredBaseCard;
                      const desiredId = Number(desiredBaseCard.id);

                      const colRect = colEl.getBoundingClientRect();
                      const centerY = colRect.top + colRect.height / 2;

                      const nodes = Array.from(
                        listEl.querySelectorAll<HTMLDivElement>(
                          `[data-card-id="${desiredId}"][data-card-index]`,
                        ),
                      );

                      // ab almost always nodes milenge ✅
                      if (!nodes.length) {
                        // ultra fallback
                        winnerTrackIndices[colIdx] = colCards[0]?._i ?? -1;
                        newOffsets[colIdx] = 0;
                        return;
                      }

                      let bestNode = nodes[0];
                      let bestDist = Infinity;
                      let bestCardIdx = Number(
                        bestNode.getAttribute("data-card-index") || 0,
                      );

                      nodes.forEach((node) => {
                        const idxAttr = node.getAttribute("data-card-index");
                        if (idxAttr == null) return;
                        const idx = Number(idxAttr);

                        const r = node.getBoundingClientRect();
                        const nodeCenter = r.top + r.height / 2;
                        const d = Math.abs(nodeCenter - centerY);
                        if (d < bestDist) {
                          bestDist = d;
                          bestNode = node;
                          bestCardIdx = idx;
                        }
                      });

                      const chosenMeta = colCards[bestCardIdx];
                      if (chosenMeta)
                        winnerTrackIndices[colIdx] = chosenMeta._i;

                      const winRect = bestNode.getBoundingClientRect();
                      const winCenter = winRect.top + winRect.height / 2;
                      newOffsets[colIdx] = centerY - winCenter;
                    });

                    setWinners(pickedWinners as Card[]);
                    setWinnerTrackByCol(winnerTrackIndices);
                    setColumnOffsets(newOffsets);
                    setStopAligned(true);
                    clearTimeout(safetyTimeout);
                    setTimeout(() => {
                      setPhase("showWinners");
                      setTimeout(() => setSpinning(false), afterRevealDelay);
                    }, STOP_TRANSITION_MS + 50);
                  });
                });
              }

              // 6) STOP → SHOW WINNERS
              // setTimeout(() => {
              //   setPhase("showWinners");

              //   // 7) DONE
              //   setTimeout(() => {
              //     setSpinning(false);
              //   }, afterRevealDelay);
              // }, beforeRevealDelay);
              // ✅ Only for MODE 1 (horizontal). Modes 2–6 do their own reveal after STOP_TRANSITION_MS.
              if (selectedMode === 1) {
                setTimeout(() => {
                  setPhase("showWinners");
                  setTimeout(() => setSpinning(false), afterRevealDelay);
                }, beforeRevealDelay);
              }
            }, slowestTime);
          }, slowerTime);
        }, slowTime);
      }, fastTime);
    }, accelTime);
  };

  const handleOpenBox = () => {
    const price = selectedMode * 200;
    alert(`Box opening functionality - $${price}`);
  };

  // columns length change ho to reset
  useEffect(() => {
    setCenterIndices(new Array(columns.length).fill(-1));
  }, [columns.length]);

  useEffect(() => {
    let frameId: number;

    const activeSpinPhases = [
      "accelerating",
      "fast",
      "slow",
      "slower",
      "slowest",
    ] as const;

    const isSpinningPhase = activeSpinPhases.includes(phase as any);

    if (!isSpinningPhase) {
      // spin khatam ya idle = center zoom band
      return;
    }

    const loop = () => {
      setCenterIndices((prev) => {
        const next = [...prev];

        columnRefs.current.forEach((colEl, colIdx) => {
          if (!colEl) return;

          const colRect = colEl.getBoundingClientRect();
          const colCenter = colRect.top + colRect.height / 2;

          const items =
            colEl.querySelectorAll<HTMLDivElement>("[data-card-index]");
          let bestIdx = -1;
          let bestDist = Infinity;

          items.forEach((item) => {
            const idxAttr = item.getAttribute("data-card-index");
            if (idxAttr == null) return;
            const idx = Number(idxAttr);

            const r = item.getBoundingClientRect();
            const itemCenter = r.top + r.height / 2;
            const d = Math.abs(itemCenter - colCenter);

            if (d < bestDist) {
              bestDist = d;
              bestIdx = idx;
            }
          });

          next[colIdx] = bestIdx;
        });

        return next;
      });

      frameId = requestAnimationFrame(loop);
    };

    frameId = requestAnimationFrame(loop);

    return () => {
      if (frameId) cancelAnimationFrame(frameId);
    };
  }, [phase, columns.length]);

  const handleModeChange = (num: number) => {
    if (spinning) return;
    // if (lockedMode) return;
    setSelectedMode(num);
    setWinners([]);
    setTargetIndices([]);
    setOffset(0);
    setColumnOffsets([]);
    setPhase("idle");

    // Sirf ye 3 lines add karo
    if (num > 1) {
      setTimeout(() => {
        columnRefs.current.forEach((col, idx) => {
          if (col) {
            col.classList.add(
              idx % 2 === 0 ? "zigzag-animate-even" : "zigzag-animate-odd",
            );
            setTimeout(() => {
              col.classList.remove("zigzag-animate-even", "zigzag-animate-odd");
            }, 600);
          }
        });
      }, 50);
    }
  };

  const getAnimationClass = () => {
    switch (phase) {
      case "accelerating":
        return "animate-accelerate";
      case "fast":
        return "animate-fast";
      case "slow":
        return "animate-slow";
      case "slower":
        return "animate-slower";
      case "slowest":
        return "animate-slowest";
      case "stopping":
        return "animate-stop";
      default:
        return "";
    }
  };

  const renderContent = () => {
    if (cardsLoading) {
      return (
        <div className="flex w-full h-24 items-center justify-center">
          <div className="w-8 h-8 border-4 border-white/20 border-t-white rounded-full animate-spin" />
        </div>
      );
    }

    if (cardsError) {
      return (
        <div className="w-full h-[250px] flex flex-col gap-3 items-center justify-center">
          <p className="text-sm text-red-400">{cardsError}</p>
          <button
            onClick={freeSpin}
            className="px-4 py-2 rounded bg-white/10 hover:bg-white/20 text-sm"
          >
            Retry
          </button>
        </div>
      );
    }

    if (!cards.length) {
      return (
        <div className="w-full h-62.5 flex items-center justify-center">
          <p className="text-sm opacity-80">No cards found.</p>
        </div>
      );
    }
    // ==========================
    // MODE 1: HORIZONTAL STRIP
    // ==========================
    if (selectedMode === 1) {
      return (
        <>
          <CardTrack
            trackRef={trackRef}
            cardRefs={cardRefs}
            track={track}
            phase={phase}
            offset={offset}
            segWidth={segWidth}
            centerIndex={centerIndex}
            targetIndices={targetIndices}
            getAnimationClass={getAnimationClass}
          />
        </>
      );
    }

    // ==========================
    // MODES 2–6: VERTICAL COLUMNS
    // ==========================

    const getVerticalClass = () => {
      if (phase === "accelerating") return "animate-accelerate-vertical";
      if (phase === "fast") return "animate-fast-vertical";
      if (phase === "slow") return "animate-slow-vertical";
      if (phase === "slower") return "animate-slower-vertical";
      if (phase === "slowest") return "animate-slowest-vertical";
      if (phase === "stopping" || phase === "showWinners") return "";
      return "";
    };

    const verticalClass = getVerticalClass();

    return (
      <>
        <CardColumns
          stopAligned={stopAligned}
          winnerIdByCol={winnerIdByCol}
          listRefs={listRefs}
          winnerTrackByCol={winnerTrackByCol}
          backendRawValues={backendRawValues}
          spinValues={spinValues}
          baseIndexById={baseIndexById}
          frozenY={frozenY}
          setFrozenY={setFrozenY}
          selectedMode={selectedMode}
          columns={columns}
          winners={winners}
          columnRefs={columnRefs}
          phase={phase}
          CARD_W={CARD_W}
          columnOffsets={columnOffsets}
          segWidth={segWidth}
          verticalClass={verticalClass}
          targetIndices={targetIndices}
          centerIndices={centerIndices}
        />
      </>
    );
  };

  return (
    <>
      <BoxLayout
        box={box}
        boltMode={boltMode}
        selectedMode={selectedMode}
        spinning={spinning}
        viewportRef={viewportRef}
        renderContent={renderContent}
        handleOpenBox={handleOpenBox}
        handleFreeSpin={handleFreeSpin}
        handleModeChange={handleModeChange}
        boxId={boxId}
      />
      <AlertModal
        open={modalOpen}
        type={modalType}
        message={modalMsg}
        onClose={() => setModalOpen(false)}
      />
      <WhatsInsideTheBoxGrid track={cards} qty={selectedMode} />
    </>
  );
}
