﻿// Main app shell ÃƒÆ’Ã†â€™Ãƒâ€šÃ‚Â¢ÃƒÆ’Ã‚Â¢ÃƒÂ¢Ã¢â€šÂ¬Ã…Â¡Ãƒâ€šÃ‚Â¬ÃƒÆ’Ã‚Â¢ÃƒÂ¢Ã¢â‚¬Å¡Ã‚Â¬Ãƒâ€šÃ‚Â wires everything together
const { useState: useStateA, useEffect: useEffectA, useMemo: useMemoA, useCallback: useCallbackA, useRef: useRefA } = React;

// Default collection state ÃƒÆ’Ã†â€™Ãƒâ€šÃ‚Â¢ÃƒÆ’Ã‚Â¢ÃƒÂ¢Ã¢â€šÂ¬Ã…Â¡Ãƒâ€šÃ‚Â¬ÃƒÆ’Ã‚Â¢ÃƒÂ¢Ã¢â‚¬Å¡Ã‚Â¬Ãƒâ€šÃ‚Â empty; keyed by sticker id: { rarity, count, isNew }
const STORAGE_KEY = 'wc26-collectibles-v1';
const DAILY_GAME_CONFIG = {
  dailyPack: true,
  quiz: true,
  slot: true,
  wheel: true,
};
const LEADERBOARD_LIMIT = 5;
const LEADERBOARD_GAME_KEYS = ['volley', 'quizStreak'];

function getGmtDayKey(ts = Date.now()) {
  return new Date(ts).toISOString().slice(0, 10);
}

function getNextGmtMidnightTs(ts = Date.now()) {
  const now = new Date(ts);
  return Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 1);
}

function getDailyResetCountdown(ts = Date.now()) {
  const diff = Math.max(0, getNextGmtMidnightTs(ts) - ts);
  const totalMinutes = Math.ceil(diff / (60 * 1000));
  const hours = Math.floor(totalMinutes / 60);
  const minutes = totalMinutes % 60;
  return {
    ms: diff,
    hours,
    minutes,
    label: minutes ? `${hours}h ${minutes}m left` : `${hours}h left`,
  };
}

function sortLeaderboardEntries(entries) {
  return [...(entries || [])]
    .sort((a, b) => (b.score - a.score) || (b.distance - a.distance) || ((a.createdAt || 0) - (b.createdAt || 0)))
    .slice(0, LEADERBOARD_LIMIT);
}

function createEmptyLeaderboards() {
  return LEADERBOARD_GAME_KEYS.reduce((acc, gameKey) => {
    acc[gameKey] = [];
    return acc;
  }, {});
}

function createEmptyPersonalBests() {
  return LEADERBOARD_GAME_KEYS.reduce((acc, gameKey) => {
    acc[gameKey] = 0;
    return acc;
  }, {});
}

function normalizeLeaderboards(raw, legacyVolley = []) {
  const next = createEmptyLeaderboards();
  if (Array.isArray(legacyVolley) && legacyVolley.length) next.volley = sortLeaderboardEntries(legacyVolley);
  if (!raw || typeof raw !== 'object') return next;
  LEADERBOARD_GAME_KEYS.forEach(gameKey => {
    if (Array.isArray(raw[gameKey])) next[gameKey] = sortLeaderboardEntries(raw[gameKey]);
  });
  return next;
}

function normalizePersonalBests(raw, leaderboards) {
  const next = createEmptyPersonalBests();
  LEADERBOARD_GAME_KEYS.forEach(gameKey => {
    const topScore = leaderboards?.[gameKey]?.[0]?.score ?? 0;
    next[gameKey] = Number.isFinite(raw?.[gameKey]) ? raw[gameKey] : topScore;
  });
  return next;
}

function upsertLeaderboardEntry(entries, entry) {
  const next = [...(entries || [])];
  const matchIndex = next.findIndex(item => (
    (entry.userId && item.userId && item.userId === entry.userId) ||
    (!entry.userId && item.name === entry.name)
  ));

  if (matchIndex >= 0) {
    if ((next[matchIndex]?.score || 0) >= entry.score) return sortLeaderboardEntries(next);
    next[matchIndex] = { ...next[matchIndex], ...entry };
  } else {
    next.push(entry);
  }

  return sortLeaderboardEntries(next);
}

function loadState() {
  try {
    const raw = localStorage.getItem(STORAGE_KEY);
    if (!raw) return null;
    return JSON.parse(raw);
  } catch { return null; }
}
function saveState(s) {
  try { localStorage.setItem(STORAGE_KEY, JSON.stringify(s)); } catch {}
}

const DEFAULT_PROGRESS = {
  coins: 500,
  collection: {},
  theme: 'classic',
  dailyGamePlays: {},
  leaderboards: createEmptyLeaderboards(),
  personalBests: createEmptyPersonalBests(),
};

function normalizeProgress(raw) {
  const leaderboards = normalizeLeaderboards(raw?.leaderboards, raw?.volleyLeaderboard);
  return {
    coins: Number.isFinite(raw?.coins) ? raw.coins : DEFAULT_PROGRESS.coins,
    collection: raw?.collection && typeof raw.collection === 'object' ? raw.collection : {},
    theme: typeof raw?.theme === 'string' ? raw.theme : DEFAULT_PROGRESS.theme,
    dailyGamePlays: raw?.dailyGamePlays && typeof raw.dailyGamePlays === 'object' ? raw.dailyGamePlays : {},
    leaderboards,
    personalBests: normalizePersonalBests(raw?.personalBests, leaderboards),
  };
}

const RARITY_ALIAS = { shiny: 'rare', holo: 'epic', legend: 'legendary' };
function normalizeRarity(r) { return RARITY_ALIAS[r] || r; }

function orderMax(a, b) {
  const order = ['common', 'rare', 'epic', 'legendary'];
  return order.indexOf(normalizeRarity(a)) > order.indexOf(normalizeRarity(b)) ? a : b;
}

function mergeCollection(localCollection, remoteCollection) {
  const merged = { ...(remoteCollection || {}) };
  Object.entries(localCollection || {}).forEach(([stickerId, localEntry]) => {
    const remoteEntry = merged[stickerId];
    if (!remoteEntry) {
      merged[stickerId] = localEntry;
      return;
    }
    merged[stickerId] = {
      rarity: orderMax(remoteEntry.rarity || 'common', localEntry.rarity || 'common'),
      count: Math.max(remoteEntry.count || 0, localEntry.count || 0),
      isNew: Boolean(remoteEntry.isNew || localEntry.isNew),
    };
  });
  return merged;
}

function mergeProgress(localState, remoteState) {
  const localProgress = normalizeProgress(localState);
  const remoteProgress = normalizeProgress(remoteState);
  return {
    coins: Math.max(localProgress.coins, remoteProgress.coins),
    collection: mergeCollection(localProgress.collection, remoteProgress.collection),
    theme: remoteProgress.theme || localProgress.theme || DEFAULT_PROGRESS.theme,
    dailyGamePlays: { ...(remoteProgress.dailyGamePlays || {}), ...(localProgress.dailyGamePlays || {}) },
    leaderboards: localProgress.leaderboards,
    personalBests: localProgress.personalBests,
  };
}

function formatAuthName(user) {
  if (!user) return 'Guest';
  return (user.displayName || user.email || 'Player').slice(0, 24);
}

function SectionHeader({ icon, title, description, action }) {
  return (
    <div className="section-head">
      <div className="section-head__copy">
        <div className="section-head__title-wrap">
          <span className="section-head__icon" aria-hidden="true">{icon}</span>
          <h2>{title}</h2>
        </div>
        <p>{description}</p>
      </div>
      {action ? <div className="section-head__action">{action}</div> : null}
    </div>
  );
}

function CollectionProgressCard({ totalOwned, totalTotal, onClick }) {
  const progress = totalTotal ? totalOwned / totalTotal : 0;
  const radius = 86;
  const circumference = 2 * Math.PI * radius;
  const dashOffset = circumference * (1 - progress);

  return (
    <div className="collection-card">
      <div className="collection-card__title display">Collection Progress</div>
      <div className="collection-card__ring">
        <svg viewBox="0 0 220 220" aria-hidden="true">
          <circle className="collection-card__ring-track" cx="110" cy="110" r={radius} />
          <circle
            className="collection-card__ring-value"
            cx="110"
            cy="110"
            r={radius}
            strokeDasharray={circumference}
            strokeDashoffset={dashOffset}
          />
        </svg>
        <div className="collection-card__ring-copy">
          <strong>{totalOwned}/{totalTotal}</strong>
          <span>{Math.round(progress * 100)}% complete</span>
        </div>
      </div>
      <button className="btn btn-progress btn-sm" onClick={onClick}>View Collection</button>
    </div>
  );
}

function HubTile({ icon, title, sub, reward, rewardClassName = 'coin', grad, onClick, countdown }) {
  return (
    <div className="hub-tile" style={{ '--tile-grad': grad }} onClick={onClick}>
      <div className="hub-tile__top">
        <div className="hub-tile__icon">{icon}</div>
        <div className="hub-tile__copy">
          <div className="hub-tile__title">{title}</div>
          <div className="hub-tile__sub">{sub}</div>
        </div>
      </div>
      <div className="hub-tile__bottom">
        {countdown && <div className="hub-tile__timer">{countdown}</div>}
        <div className="hub-tile__footer">
          {reward && <div className={`hub-tile__reward ${rewardClassName}`.trim()}>{reward}</div>}
          <div className="hub-tile__arrow" aria-hidden="true">›</div>
        </div>
      </div>
    </div>
  );
}

function Footer({ onLinkClick }) {
  const links = ['About', 'FAQ', 'Support', 'Terms', 'Privacy'];
  const socials = ['X', 'Discord', 'Instagram'];

  return (
    <footer className="footer">
      <div className="footer__brand">
        <div className="logo footer__logo">
          <div className="logo__mark" />
          <div>
            <span>WC '26</span>
            <small>Unofficial Fan Collectibles</small>
          </div>
        </div>
      </div>
      <div className="footer__links">
        {links.map(label => (
          <button key={label} className="footer__link" onClick={() => onLinkClick(label)}>{label}</button>
        ))}
      </div>
      <div className="footer__meta">
        <span>&copy; 2026 WC '26 Collectibles. Not affiliated with FIFA or any official entity.</span>
      </div>
      <div className="footer__socials">
        {socials.map(label => (
          <button key={label} className="footer__social" onClick={() => onLinkClick(label)} aria-label={label}>{label}</button>
        ))}
      </div>
    </footer>
  );
}

function HomeView({ onNav, onOpenPack, coins, collection, leaderboards, dailyStatus, signedIn }) {
  const data = window.WC_DATA;
  const totalOwned = data.STICKERS.filter(s => collection[s.id]?.count > 0).length;
  const totalTotal = data.STICKERS.length;
  const bestVolley = leaderboards.volley[0]?.score ?? 0;
  const bestQuizStreak = leaderboards.quizStreak[0]?.score ?? 0;

  return (
    <div className="fade-in">
      <div className="hero">
        <div className="hero__content">
          <div className="hero__kicker">WC '26 • Unofficial Fan Collectibles</div>
          <h1>Collect the <em>Legends.</em></h1>
          <p className="hero__lead">Play games, earn gold, buy packs, and chase cards to complete your collection.</p>
          <div className="hero__cta">
            <button className="btn btn-gold btn-lg hero__primary" onClick={() => onNav('shop')}>Open a Pack</button>
            <button className="btn btn-hero-secondary btn-lg" onClick={() => onNav('book')}>
              <span className="btn__stack">
                <strong>View Collection</strong>
                <small>{totalOwned}/{totalTotal}</small>
              </span>
            </button>
          </div>
        </div>
      </div>

      <div className="section section-shell">
        <SectionHeader
          icon={'✦'}
          title="Daily Quests"
          description="Play each quest once for gold. All daily quests reset at midnight GMT."
        />
        <div className="home-grid home-grid--three">
          <HubTile icon={'\uD83C\uDFAF'} title="Daily Quiz" sub="Test your football knowledge."
            reward="Up to 200"
            countdown={dailyStatus.quiz.countdown.label}
            grad="linear-gradient(135deg, rgba(58,78,171,0.96) 0%, rgba(25,33,92,0.92) 100%)"
            onClick={() => onNav('quiz')} />
          <HubTile icon={'\uD83C\uDFB0'} title="Daily Slots" sub="Spin and win big prizes."
            reward="Up to 777"
            countdown={dailyStatus.slot.countdown.label}
            grad="linear-gradient(135deg, rgba(149,42,48,0.96) 0%, rgba(98,24,32,0.92) 100%)"
            onClick={() => onNav('slot')} />
          <HubTile icon={'\uD83C\uDFA1'} title="Daily Spin" sub="Spin the wheel, win gold."
            reward="Up to 1000"
            countdown={dailyStatus.wheel.countdown.label}
            grad="linear-gradient(135deg, rgba(163,117,38,0.96) 0%, rgba(112,76,21,0.9) 100%)"
            onClick={() => onNav('wheel')} />
        </div>
      </div>

      <div className="section section-shell">
        <SectionHeader
          icon={'★'}
          title="Featured"
          description="Check out the latest packs and offers."
          action={<button className="btn btn-ghost btn-sm" onClick={() => onNav('shop')}>View Shop</button>}
        />
        <div className="featured-grid">
          {data.PACKS.slice(0, 4).map(p => (
            <ShopTile
              key={p.id}
              pack={p}
              coins={coins}
              onBuy={() => onOpenPack(p)}
              dailyPackStatus={dailyStatus.dailyPack}
            />
          ))}
          <CollectionProgressCard totalOwned={totalOwned} totalTotal={totalTotal} onClick={() => onNav('book')} />
        </div>
      </div>

      <div className="section section-shell">
        <SectionHeader
          icon={'🏆'}
          title="Leaderboard Challenge"
          description={signedIn ? 'Compete globally. Climb the ranks. Earn glory.' : 'Compete globally. Sign in to publish your best scores.'}
          action={<button className="btn btn-ghost btn-sm" onClick={() => onNav('volley')}>View Leaderboards</button>}
        />
        <div className="home-grid home-grid--two">
          <HubTile icon={'\u26BD'} title="Golden Volley" sub={bestVolley ? 'Repeatable challenge • global best ' + bestVolley : 'Repeatable challenge • set the first world record.'}
            reward="Leaderboard"
            rewardClassName=""
            grad="linear-gradient(135deg, rgba(25,104,46,0.96) 0%, rgba(11,58,24,0.92) 100%)"
            onClick={() => onNav('volley')} />
          <HubTile icon={'\uD83D\uDD25'} title="Quiz Streak" sub={bestQuizStreak ? 'Keep answering until one miss • global best ' + bestQuizStreak : 'Keep answering until one miss • set the opening streak.'}
            reward="Global Best"
            rewardClassName=""
            grad="linear-gradient(135deg, rgba(29,64,123,0.96) 0%, rgba(12,35,76,0.92) 100%)"
            onClick={() => onNav('streak')} />
        </div>
      </div>
    </div>
  );
}

function ShopTile({ pack, coins = 0, onClick, onBuy, dailyPackStatus }) {
  const isFreePack = Boolean(pack.isFree);
  const canClaimFreePack = !isFreePack || dailyPackStatus?.canPlay;
  const canAfford = isFreePack ? canClaimFreePack : coins >= pack.price;
  const isDisabled = Boolean(onBuy) && !canAfford;
  const footerLabel = isFreePack
    ? (dailyPackStatus?.canPlay ? 'Free Pack' : 'Claimed Today')
    : pack.price.toLocaleString();
  const footerMeta = isFreePack
    ? (dailyPackStatus?.canPlay ? 'Claim now' : dailyPackStatus?.countdown.label)
    : (canAfford ? 'Open now' : `Need ${(pack.price - coins).toLocaleString()} more`);

  return (
    <div
      className={`shop-tile ${isFreePack ? 'is-free-pack' : ''} ${isDisabled ? 'is-disabled' : ''}`}
      style={{ '--tile-grad': pack.gradient }}
      onClick={() => { if (!isDisabled) (onBuy || onClick) && (onBuy || onClick)(); }}
    >
      <div className="shop-tile__name">{pack.name}</div>
      <div className="shop-tile__pack">
        <img src={pack.image} alt={pack.name} className="shop-tile__pack-image" loading="lazy" />
      </div>
      <div className="shop-tile__detail">
        <strong>{pack.tagline}</strong>
        <span>{pack.highlight}</span>
      </div>
      <div className="shop-tile__footer">
        <div className={`shop-tile__pill ${isFreePack ? 'is-free-pack' : ''}`}>
          <div className="shop-tile__pill-main">
            {!isFreePack && <span className="coin" />}
            <strong>{footerLabel}</strong>
          </div>
          <small>{footerMeta}</small>
        </div>
      </div>
    </div>
  );
}

function ShopView({ coins, onBuy, dailyPackStatus }) {
  const data = window.WC_DATA;
  return (
    <div className="fade-in">
      <SectionHeader
        icon={'★'}
        title="Pack Shop"
        description="Spend your gold, claim the daily free pack, and chase the legends."
        action={<div className="topbar__wallet coin">{coins}</div>}
      />
      <div className="shop-grid">
        {data.PACKS.map(p => (
          <ShopTile key={p.id} pack={p} coins={coins} onBuy={() => onBuy(p)} dailyPackStatus={dailyPackStatus} />
        ))}
      </div>
      <div className="shop-odds">
        <div className="display" style={{ fontSize: 13, letterSpacing: '0.15em', color: 'var(--ink)', marginBottom: 8 }}>Rarity Odds</div>
        <div className="row-wrap" style={{ gap: 16 }}>
          <span className="rarity-chip" data-rarity="common">{'Common • 70%'}</span>
          <span className="rarity-chip" data-rarity="rare">{'Rare • 20%'}</span>
          <span className="rarity-chip" data-rarity="epic">{'Epic • 8%'}</span>
          <span className="rarity-chip" data-rarity="legendary">{'Legendary • 2%'}</span>
        </div>
      </div>
    </div>
  );
}

function TweaksPanel({ active, theme, setTheme, onGrantCoins, onReset, onClose }) {
  if (!active) return null;
  return (
    <div className="tweaks-panel">
      <div className="row" style={{ justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 }}>
        <h4 style={{ margin: 0 }}>Tweaks</h4>
        <button style={{ color: 'var(--ink-dim)', fontSize: 18 }} onClick={onClose}>{'\u00D7'}</button>
      </div>
      <div className="tweaks-panel__row">
        <label>Theme</label>
        <div className="tweaks-panel__themes">
          {['classic','premium','neon'].map(t => (
            <button key={t} className="tweaks-panel__theme" data-theme={t} data-active={theme === t} onClick={() => setTheme(t)}>{t}</button>
          ))}
        </div>
      </div>
      <div className="tweaks-panel__row">
        <label>Demo helper</label>
        <div className="row" style={{ gap: 8 }}>
          <button className="btn btn-gold btn-sm" onClick={() => onGrantCoins(2500)} style={{ flex: 1 }}>+2500 coins</button>
          <button className="btn btn-ghost btn-sm" onClick={onReset}>Reset</button>
        </div>
      </div>
    </div>
  );
}

function App() {
  const data = window.WC_DATA;
  const firebaseSvc = window.WC_FIREBASE || { enabled: false, error: 'Firebase bootstrap not found' };
  const initialState = normalizeProgress(loadState());
  const leaderboardUnsubRef = useRefA([]);
  const saveTimerRef = useRefA(null);
  const profileLoadedRef = useRefA(false);
  const [view, setView] = useStateA('home');
  const [coins, setCoins] = useStateA(initialState.coins);
  const [collection, setCollection] = useStateA(initialState.collection); // { stickerId: { rarity, count, isNew } }
  const [leaderboards, setLeaderboards] = useStateA(initialState.leaderboards);
  const [personalBests, setPersonalBests] = useStateA(initialState.personalBests);
  const [pack, setPack] = useStateA(null); // active opening
  const [rolls, setRolls] = useStateA([]);
  const [playerModal, setPlayerModal] = useStateA(null); // { sticker, rarity }
  const [toasts, setToasts] = useStateA([]);
  const [theme, setTheme] = useStateA(initialState.theme);
  const [dailyGamePlays, setDailyGamePlays] = useStateA(initialState.dailyGamePlays);
  const [dailyTick, setDailyTick] = useStateA(Date.now());
  const [tweaksOpen, setTweaksOpen] = useStateA(false);
  const [tweaksAvail, setTweaksAvail] = useStateA(false);
  const [authReady, setAuthReady] = useStateA(!firebaseSvc.enabled);
  const [user, setUser] = useStateA(null);
  const [cloudStatus, setCloudStatus] = useStateA(firebaseSvc.enabled ? 'Waiting for sign in' : (firebaseSvc.error || 'Firebase not configured'));
  const [openMenu, setOpenMenu] = useStateA(null);
  const [mobileNavOpen, setMobileNavOpen] = useStateA(false);

  useEffectA(() => {
    saveState({ coins, collection, leaderboards, personalBests, theme, dailyGamePlays });
  }, [coins, collection, leaderboards, personalBests, theme, dailyGamePlays]);

  useEffectA(() => {
    const timer = setInterval(() => setDailyTick(Date.now()), 60 * 1000);
    return () => clearInterval(timer);
  }, []);

  // Apply theme to root
  useEffectA(() => {
    document.documentElement.setAttribute('data-theme', theme);
  }, [theme]);

  useEffectA(() => () => {
    leaderboardUnsubRef.current.forEach(unsub => unsub && unsub());
    if (saveTimerRef.current) clearTimeout(saveTimerRef.current);
  }, []);

  // Tweaks postMessage protocol
  useEffectA(() => {
    function onMsg(e) {
      if (e.data?.type === '__activate_edit_mode') { setTweaksAvail(true); setTweaksOpen(true); }
      if (e.data?.type === '__deactivate_edit_mode') { setTweaksOpen(false); }
    }
    window.addEventListener('message', onMsg);
    window.parent.postMessage({ type: '__edit_mode_available' }, '*');
    return () => window.removeEventListener('message', onMsg);
  }, []);

  useEffectA(() => {
    if (!firebaseSvc.enabled) return undefined;

    const unsubscribe = firebaseSvc.auth.onAuthStateChanged(async nextUser => {
      setUser(nextUser);
      setAuthReady(true);

      if (!nextUser) {
        profileLoadedRef.current = false;
        setCloudStatus('Playing locally');
        return;
      }

      setCloudStatus('Syncing profile');

      try {
        const userRef = firebaseSvc.db.collection('users').doc(nextUser.uid);
        const snapshot = await userRef.get();
        const remoteProgress = snapshot.exists ? snapshot.data() : null;
        const merged = mergeProgress(loadState(), remoteProgress);

        setCoins(merged.coins);
        setCollection(merged.collection);
        setTheme(merged.theme);
        setDailyGamePlays(merged.dailyGamePlays);
        setLeaderboards(merged.leaderboards);
        setPersonalBests(merged.personalBests);

        await userRef.set({
          coins: merged.coins,
          collection: merged.collection,
          theme: merged.theme,
          dailyGamePlays: merged.dailyGamePlays,
          personalBests: merged.personalBests,
          displayName: formatAuthName(nextUser),
          email: nextUser.email || null,
          photoURL: nextUser.photoURL || null,
          updatedAt: firebase.firestore.FieldValue.serverTimestamp(),
        }, { merge: true });

        profileLoadedRef.current = true;
        setCloudStatus('Cloud sync active');
      } catch (error) {
        console.error('Failed to sync Firebase profile', error);
        setCloudStatus('Cloud sync failed');
        addToast('Firebase profile sync failed');
      }
    });

    return () => unsubscribe();
  }, []);

  useEffectA(() => {
    if (!firebaseSvc.enabled) return undefined;

    leaderboardUnsubRef.current = LEADERBOARD_GAME_KEYS.map(gameKey => firebaseSvc.db
      .collection('leaderboards')
      .doc(gameKey)
      .collection('scores')
      .orderBy('score', 'desc')
      .limit(LEADERBOARD_LIMIT)
      .onSnapshot(snapshot => {
        const entries = snapshot.docs.map(doc => {
          const item = doc.data();
          return {
            userId: item.userId || doc.id,
            name: item.name || 'YOU',
            score: item.score || 0,
            distance: item.distance || 0,
            bestCombo: item.bestCombo || 0,
            createdAt: item.createdAt?.toMillis ? item.createdAt.toMillis() : (item.createdAt || 0),
          };
        });
        setLeaderboards(prev => ({ ...prev, [gameKey]: entries }));
      }, error => {
        console.error(`Failed to load ${gameKey} leaderboard`, error);
      }));

    return () => {
      leaderboardUnsubRef.current.forEach(unsub => unsub && unsub());
      leaderboardUnsubRef.current = [];
    };
  }, []);

  useEffectA(() => {
    if (!firebaseSvc.enabled || !authReady || !user || !profileLoadedRef.current) return undefined;
    if (saveTimerRef.current) clearTimeout(saveTimerRef.current);

    saveTimerRef.current = setTimeout(async () => {
      try {
        await firebaseSvc.db.collection('users').doc(user.uid).set({
          coins,
          collection,
          theme,
          dailyGamePlays,
          personalBests,
          displayName: formatAuthName(user),
          email: user.email || null,
          photoURL: user.photoURL || null,
          updatedAt: firebase.firestore.FieldValue.serverTimestamp(),
        }, { merge: true });
      } catch (error) {
        console.error('Failed to save Firebase profile', error);
      }
    }, 500);

    return () => {
      if (saveTimerRef.current) clearTimeout(saveTimerRef.current);
    };
  }, [coins, collection, theme, dailyGamePlays, personalBests, authReady, user]);

  useEffectA(() => {
    function handlePointerDown(event) {
      if (event.target.closest('.topbar__nav') || event.target.closest('.topbar__mobile-toggle')) return;
      setOpenMenu(null);
      setMobileNavOpen(false);
    }

    document.addEventListener('pointerdown', handlePointerDown);
    return () => document.removeEventListener('pointerdown', handlePointerDown);
  }, []);

  function addToast(text) {
    const id = Math.random();
    setToasts(t => [...t, { id, text }]);
    setTimeout(() => setToasts(t => t.filter(x => x.id !== id)), 2800);
  }

  function navigate(nextView) {
    setView(nextView);
    setOpenMenu(null);
    setMobileNavOpen(false);
  }

  function earnCoins(n) { setCoins(c => c + n); }
  function spendCoins(n) { setCoins(c => c - n); }
  function markDailyGamePlayed(gameId) {
    const dayKey = getGmtDayKey();
    setDailyGamePlays(prev => {
      if (prev?.[gameId] === dayKey) return prev;
      return { ...(prev || {}), [gameId]: dayKey };
    });
  }

  function hasPlayedDailyGame(gameId, ts = dailyTick) {
    return DAILY_GAME_CONFIG[gameId] ? dailyGamePlays?.[gameId] === getGmtDayKey(ts) : false;
  }

  function getLeaderboardIdentity(gameKey) {
    return {
      name: (user ? formatAuthName(user) : 'YOU').slice(0, 24),
      userId: user?.uid || `local-${gameKey}`,
    };
  }

  async function saveLeaderboardScore(gameKey, entry) {
    const identity = getLeaderboardIdentity(gameKey);
    const nextEntry = {
      ...entry,
      ...identity,
      createdAt: Date.now(),
    };

    if (!firebaseSvc.enabled || !user) {
      const currentBest = personalBests[gameKey] || 0;
      if (nextEntry.score <= currentBest) {
        return { saved: false, best: currentBest, scope: 'local' };
      }

      setPersonalBests(prev => ({ ...prev, [gameKey]: nextEntry.score }));
      setLeaderboards(prev => ({ ...prev, [gameKey]: upsertLeaderboardEntry(prev[gameKey], nextEntry) }));

      if (firebaseSvc.enabled && !user) addToast('Sign in to publish leaderboard scores globally');
      return { saved: true, best: nextEntry.score, scope: 'local' };
    }

    try {
      const scoreRef = firebaseSvc.db
        .collection('leaderboards')
        .doc(gameKey)
        .collection('scores')
        .doc(user.uid);

      const snapshot = await scoreRef.get();
      const existing = snapshot.exists ? snapshot.data() : null;
      const currentBest = existing?.score || 0;

      if (nextEntry.score <= currentBest) {
        setPersonalBests(prev => ({ ...prev, [gameKey]: Math.max(prev[gameKey] || 0, currentBest) }));
        return { saved: false, best: currentBest, scope: 'global' };
      }

      setPersonalBests(prev => ({ ...prev, [gameKey]: nextEntry.score }));
      setLeaderboards(prev => ({ ...prev, [gameKey]: upsertLeaderboardEntry(prev[gameKey], nextEntry) }));

      await scoreRef.set({
        ...nextEntry,
        userId: user.uid,
        createdAt: existing?.createdAt || firebase.firestore.FieldValue.serverTimestamp(),
        updatedAt: firebase.firestore.FieldValue.serverTimestamp(),
      }, { merge: true });

      return { saved: true, best: nextEntry.score, scope: 'global' };
    } catch (error) {
      console.error(`Failed to save ${gameKey} leaderboard score`, error);
      addToast('Leaderboard save failed');
      return { saved: false, best: personalBests[gameKey] || 0, scope: 'error' };
    }
  }

  function openPack(p) {
    if (p.isFree) {
      if (hasPlayedDailyGame('dailyPack')) {
        addToast(`Daily free pack resets in ${getDailyResetCountdown(dailyTick).label}`);
        return;
      }
      markDailyGamePlayed('dailyPack');
      rollPack(p);
      return;
    }

    if (coins < p.price) { addToast('Not enough coins'); return; }
    spendCoins(p.price);
    rollPack(p);
  }
  function rollPack(p) {
    // Roll contents
    let pulls = [];
    for (let i = 0; i < p.size; i++) {
      const rarity = data.rollRarity(p.luck);
      const pool = data.STICKERS.filter(s => {
        // common gets all commons; shiny gets shiny-base; holo gets holo-base; legend gets legend-base ÃƒÆ’Ã†â€™Ãƒâ€šÃ‚Â¢ÃƒÆ’Ã‚Â¢ÃƒÂ¢Ã¢â€šÂ¬Ã…Â¡Ãƒâ€šÃ‚Â¬ÃƒÆ’Ã‚Â¢ÃƒÂ¢Ã¢â‚¬Å¡Ã‚Â¬Ãƒâ€šÃ‚Â with promotion allowed
        return true; // all players can appear at any rarity
      });
      const sticker = pool[Math.floor(Math.random() * pool.length)];
      pulls.push({ sticker, rarity });
    }
    // Apply pack guarantees after the roll so display promises stay accurate.
    if (p.guarantee) {
      const order = { common: 0, rare: 1, epic: 2, legendary: 3 };
      const minRarity = normalizeRarity(p.guarantee);
      const minLvl = order[minRarity];
      const targetCount = Math.min(pulls.length, Math.max(1, p.guaranteeCount || 1));

      if (Number.isFinite(minLvl)) {
        let qualifiedCount = pulls.filter(pl => order[normalizeRarity(pl.rarity)] >= minLvl).length;
        for (let i = pulls.length - 1; i >= 0 && qualifiedCount < targetCount; i--) {
          if (order[normalizeRarity(pulls[i].rarity)] >= minLvl) continue;
          pulls[i].rarity = minRarity;
          qualifiedCount += 1;
        }
      }
    }
    // Determine isNew
    const temp = { ...collection };
    pulls = pulls.map(pl => {
      const existing = temp[pl.sticker.id];
      const isNew = !existing;
      // Track temp for within-pack dupes too
      if (!existing) temp[pl.sticker.id] = { rarity: pl.rarity, count: 1, isNew: true };
      else temp[pl.sticker.id] = { ...existing, count: existing.count + 1 };
      return { ...pl, isNew };
    });
    setRolls(pulls);
    setPack(p);
  }

  function rewardPack(p) {
    rollPack(p);
  }

  function grantStickers(pulls) {
    setCollection(prev => {
      const next = { ...prev };
      let dupeCoins = 0;
      pulls.forEach(pl => {
        const cur = next[pl.sticker.id];
        if (!cur) {
          next[pl.sticker.id] = { rarity: pl.rarity, count: 1, isNew: true };
        } else {
          next[pl.sticker.id] = { ...cur, count: cur.count + 1, rarity: orderMax(cur.rarity, pl.rarity) };
          dupeCoins += 15;
        }
      });
      if (dupeCoins > 0) setTimeout(() => earnCoins(dupeCoins), 200);
      return next;
    });
  }

  function markSeen(stickerId) {
    setCollection(prev => {
      if (!prev[stickerId] || !prev[stickerId].isNew) return prev;
      return { ...prev, [stickerId]: { ...prev[stickerId], isNew: false } };
    });
  }

  function resetAll() {
    if (!confirm('Reset all progress?')) return;
    setCoins(500);
    setCollection({});
    setLeaderboards(createEmptyLeaderboards());
    setPersonalBests(createEmptyPersonalBests());
    setDailyGamePlays({});
    addToast('Progress reset');
  }

  async function signInWithGoogle() {
    if (!firebaseSvc.enabled) {
      addToast('Add your Firebase config first');
      return;
    }
    try {
      await firebaseSvc.auth.signInWithPopup(firebaseSvc.googleProvider);
    } catch (error) {
      console.error('Google sign-in failed', error);
      addToast('Google sign-in failed');
    }
  }

  async function signOutUser() {
    if (!firebaseSvc.enabled) return;
    try {
      await firebaseSvc.auth.signOut();
      addToast('Signed out');
    } catch (error) {
      console.error('Sign-out failed', error);
      addToast('Sign-out failed');
    }
  }

  const navItems = [
    { id: 'home', label: 'Home' },
    { id: 'book', label: 'Collection' },
    { id: 'shop', label: 'Shop' },
  ];
  const dailyMenuItems = [
    { id: 'quiz', label: 'Daily Quiz' },
    { id: 'slot', label: 'Daily Slots' },
    { id: 'wheel', label: 'Daily Spin' },
  ];
  const leaderboardMenuItems = [
    { id: 'volley', label: 'Golden Volley' },
    { id: 'streak', label: 'Quiz Streak' },
  ];
  const isDailyView = dailyMenuItems.some(item => item.id === view);
  const isLeaderboardView = leaderboardMenuItems.some(item => item.id === view);

  const dailyStatus = useMemoA(() => {
    const countdown = getDailyResetCountdown(dailyTick);
    return Object.keys(DAILY_GAME_CONFIG).reduce((acc, gameId) => {
      const playedToday = hasPlayedDailyGame(gameId, dailyTick);
      acc[gameId] = {
        canPlay: !playedToday,
        playedToday,
        countdown,
      };
      return acc;
    }, {});
  }, [dailyGamePlays, dailyTick]);

  return (
    <div className="app">
      <header className="topbar">
        <div className="topbar__inner">
          <div className="logo" onClick={() => navigate('home')} style={{ cursor: 'pointer' }}>
            <div className="logo__mark" />
            <span>WC '26</span>
          </div>
          <button className="topbar__mobile-toggle" onClick={() => setMobileNavOpen(open => !open)}>
            {mobileNavOpen ? 'Close' : 'Menu'}
          </button>
          <nav className="topbar__nav" data-open={mobileNavOpen}>
            {navItems.map(n => (
              <button key={n.id} data-active={view === n.id} onClick={() => navigate(n.id)}>{n.label}</button>
            ))}
            <div
              className="topbar__menu"
              onMouseEnter={() => setOpenMenu('dailies')}
              onMouseLeave={() => setOpenMenu(null)}
            >
              <button
                data-active={isDailyView}
                data-open={openMenu === 'dailies'}
                onClick={() => setOpenMenu(openMenu === 'dailies' ? null : 'dailies')}
              >
                Daily
              </button>
              <div className="topbar__submenu" hidden={openMenu !== 'dailies'}>
                {dailyMenuItems.map(item => (
                  <button key={item.id} data-active={view === item.id} onClick={() => navigate(item.id)}>{item.label}</button>
                ))}
              </div>
            </div>
            <div
              className="topbar__menu"
              onMouseEnter={() => setOpenMenu('leaderboards')}
              onMouseLeave={() => setOpenMenu(null)}
            >
              <button
                data-active={isLeaderboardView}
                data-open={openMenu === 'leaderboards'}
                onClick={() => setOpenMenu(openMenu === 'leaderboards' ? null : 'leaderboards')}
              >
                Leaderboards
              </button>
              <div className="topbar__submenu" hidden={openMenu !== 'leaderboards'}>
                {leaderboardMenuItems.map(item => (
                  <button key={item.id} data-active={view === item.id} onClick={() => navigate(item.id)}>{item.label}</button>
                ))}
              </div>
            </div>
          </nav>
          <div className="topbar__status">
            <div className="topbar__status-copy">
              <div>{authReady ? cloudStatus : 'Loading auth'}</div>
              <div>{user ? formatAuthName(user) : 'Guest mode'}</div>
            </div>
            {firebaseSvc.enabled && !user && (
              <button className="btn btn-ghost btn-sm" onClick={signInWithGoogle}>Sign in</button>
            )}
            {firebaseSvc.enabled && user && (
              <button className="btn btn-ghost btn-sm" onClick={signOutUser}>Sign out</button>
            )}
            <div className="topbar__wallet coin">{coins}</div>
          </div>
        </div>
      </header>

      <main className="main">
        {view === 'home'  && <HomeView onNav={navigate} onOpenPack={openPack} coins={coins} collection={collection} leaderboards={leaderboards} dailyStatus={dailyStatus} signedIn={!!user} />}
        {view === 'shop'  && <ShopView coins={coins} onBuy={openPack} dailyPackStatus={dailyStatus.dailyPack} />}
        {view === 'book'  && <StickerBook collection={collection} onStickerClick={(s, r) => setPlayerModal({ sticker: s, rarity: r })} onViewedNew={markSeen} />}
        {view === 'volley' && <BouncemastersGame onExit={() => navigate('home')} addToast={addToast} leaderboard={leaderboards.volley} onSubmitScore={(entry) => saveLeaderboardScore('volley', entry)} />}
        {view === 'quiz'  && <QuizGame onExit={() => navigate('home')} onEarnCoins={earnCoins} addToast={addToast} canPlay={dailyStatus.quiz.canPlay} countdownLabel={dailyStatus.quiz.countdown.label} onMarkPlayed={() => markDailyGamePlayed('quiz')} />}
        {view === 'slot'  && <SlotGame onExit={() => navigate('home')} onEarnCoins={earnCoins} addToast={addToast} canPlay={dailyStatus.slot.canPlay} countdownLabel={dailyStatus.slot.countdown.label} onMarkPlayed={() => markDailyGamePlayed('slot')} />}
        {view === 'wheel' && <WheelGame onExit={() => navigate('home')} onEarnCoins={earnCoins} onRewardPack={rewardPack} addToast={addToast} canPlay={dailyStatus.wheel.canPlay} countdownLabel={dailyStatus.wheel.countdown.label} onMarkPlayed={() => markDailyGamePlayed('wheel')} />}
        {view === 'streak' && <QuizStreakGame onExit={() => navigate('home')} addToast={addToast} leaderboard={leaderboards.quizStreak} onSubmitScore={(entry) => saveLeaderboardScore('quizStreak', entry)} />}
      </main>

      <Footer onLinkClick={(label) => addToast(`${label} coming soon`)} />

      {pack && (
        <PackOpening
          pack={pack}
          rolls={rolls}
          data={data}
          onGrantStickers={grantStickers}
          onDone={() => { setPack(null); setRolls([]); navigate('book'); }}
        />
      )}

      {playerModal && (
        <PlayerModal sticker={playerModal.sticker} rarity={playerModal.rarity} onClose={() => setPlayerModal(null)} />
      )}

      <div className="toasts">
        {toasts.map(t => <div key={t.id} className="toast">{t.text}</div>)}
      </div>

      {tweaksAvail && !tweaksOpen && (
        <button className="tweaks-fab" onClick={() => setTweaksOpen(true)} title="Tweaks">ÃƒÆ’Ã†â€™Ãƒâ€šÃ‚Â¢ÃƒÆ’Ã¢â‚¬Â¦Ãƒâ€šÃ‚Â¡ÃƒÆ’Ã‚Â¢ÃƒÂ¢Ã¢â€šÂ¬Ã…Â¾Ãƒâ€šÃ‚Â¢</button>
      )}
      <TweaksPanel
        active={tweaksOpen}
        theme={theme}
        setTheme={setTheme}
        onGrantCoins={(n) => { earnCoins(n); addToast(`+${n} coins`); }}
        onReset={resetAll}
        onClose={() => setTweaksOpen(false)}
      />
    </div>
  );
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
