import { useEffect, useMemo, useRef, useState } from 'react';
import { rarityColor } from '../rarities';

const ITEM_WIDTH = 120;
const ITEM_WIDTH_COMPACT = 72;
const BASE_SPIN_DURATION_MS = 5500;
const SPIN_SLOTS = 42;
const TAIL_SLOTS = 8;

export function spinDurationMs(animReduction = 0) {
  const pct = Math.max(0, Math.min(90, Number(animReduction) || 0));
  return Math.max(1000, Math.round(BASE_SPIN_DURATION_MS * (1 - pct / 100)));
}

function pickRandom(items, avoidId) {
  if (!items.length) return null;
  if (items.length === 1) return items[0];
  let pick = items[Math.floor(Math.random() * items.length)];
  for (let i = 0; i < 10 && pick.id === avoidId; i += 1) {
    pick = items[Math.floor(Math.random() * items.length)];
  }
  return pick;
}

function shuffledPool(items) {
  const pool = [...items];
  for (let i = pool.length - 1; i > 0; i -= 1) {
    const j = Math.floor(Math.random() * (i + 1));
    [pool[i], pool[j]] = [pool[j], pool[i]];
  }
  return pool;
}

function buildTrack(items, winnerId, spins = SPIN_SLOTS) {
  if (!items?.length) return { track: [], winnerIndex: 0 };

  const winner = items.find((i) => i.id === winnerId) || items[0];
  const track = [];
  let lastId = null;
  let bag = shuffledPool(items);
  let bagIndex = 0;

  const nextItem = () => {
    // Draw from a reshuffled bag so the strip covers the pool, not a fixed cycle
    if (bagIndex >= bag.length) {
      bag = shuffledPool(items);
      bagIndex = 0;
      if (bag.length > 1 && bag[0].id === lastId) {
        const swap = 1 + Math.floor(Math.random() * (bag.length - 1));
        [bag[0], bag[swap]] = [bag[swap], bag[0]];
      }
    }
    let item = bag[bagIndex];
    bagIndex += 1;
    if (item.id === lastId && items.length > 1) {
      item = pickRandom(items, lastId);
    }
    return item;
  };

  for (let i = 0; i < spins; i += 1) {
    const item = nextItem();
    track.push(item);
    lastId = item.id;
  }

  track.push(winner);
  lastId = winner.id;

  for (let i = 0; i < TAIL_SLOTS; i += 1) {
    const item = nextItem();
    track.push(item);
    lastId = item.id;
  }

  return { track, winnerIndex: spins };
}

export default function CaseReel({
  items,
  winnerId,
  spinning,
  onDone,
  showOwners = false,
  compact = false,
  animReduction = 0,
}) {
  const trackRef = useRef(null);
  const [offset, setOffset] = useState(0);
  const [locked, setLocked] = useState(null); // { track, winnerIndex, key }
  const onDoneRef = useRef(onDone);
  onDoneRef.current = onDone;
  const itemWidth = compact ? ITEM_WIDTH_COMPACT : ITEM_WIDTH;
  const durationMs = spinDurationMs(animReduction);

  const spinKey =
    winnerId && items?.length ? `${winnerId}:${items.map((i) => i.id).join(',')}` : '';

  const idleTrack = useMemo(() => {
    if (!items?.length) return [];
    return shuffledPool(items);
  }, [items]);

  const track =
    locked?.key === spinKey && locked.track.length ? locked.track : idleTrack;

  useEffect(() => {
    if (!spinning) return undefined;
    if (!items?.length || !winnerId) return undefined;

    const key = `${winnerId}:${items.map((i) => i.id).join(',')}`;
    const built = buildTrack(items, winnerId);
    setLocked({ ...built, key });
    let finished = false;

    const viewportCenter = (trackRef.current?.parentElement?.clientWidth || 600) / 2;
    const target =
      built.winnerIndex * itemWidth -
      viewportCenter +
      itemWidth / 2 +
      (Math.random() * 40 - 20);

    setOffset(0);
    const id = requestAnimationFrame(() => {
      requestAnimationFrame(() => setOffset(target));
    });

    const timer = setTimeout(() => {
      if (finished) return;
      finished = true;
      onDoneRef.current?.();
    }, durationMs + 80);

    return () => {
      cancelAnimationFrame(id);
      clearTimeout(timer);
      finished = true;
    };
    // intentionally only re-run when a new spin starts
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [spinning, winnerId, itemWidth, durationMs]);

  return (
    <div
      className={`reel-wrap${showOwners ? ' reel-wrap-owners' : ''}${compact ? ' reel-wrap-compact' : ''}`}
      ref={trackRef}
    >
      <div className="reel-marker" />
      <div
        className="reel-track"
        style={{
          transform: `translateX(-${offset}px)`,
          transition: spinning
            ? `transform ${durationMs}ms cubic-bezier(0.12, 0.75, 0.12, 1)`
            : 'none',
        }}
      >
        {track.map((item, idx) => (
          <div
            key={`${item.id}-${idx}`}
            className="reel-item"
            style={{
              '--rarity': rarityColor(item.rarity),
              ...(compact ? { flex: `0 0 ${itemWidth}px`, width: itemWidth } : null),
            }}
          >
            <div className="glyph" style={{ color: rarityColor(item.rarity) }}>
              {item.imageUrl ? (
                <img src={item.imageUrl} alt="" className="reel-img" />
              ) : (
                item.name.slice(0, 2).toUpperCase()
              )}
            </div>
            <div className="label">{item.name}</div>
            {showOwners && (item.ownerUsername || item.ownerAvatarUrl) ? (
              <div className="reel-owner">
                {item.ownerAvatarUrl ? (
                  <img src={item.ownerAvatarUrl} alt="" className="reel-owner-avatar" />
                ) : (
                  <span className="reel-owner-fallback">
                    {(item.ownerUsername || '?').slice(0, 1).toUpperCase()}
                  </span>
                )}
                <span className="reel-owner-name">{item.ownerUsername}</span>
              </div>
            ) : null}
          </div>
        ))}
      </div>
    </div>
  );
}
