// Wordra production app shell — wires the playable game flow to Firebase.
// First launch: language picker → onboarding → home. Subsequent launches go
// straight to home. Daily mode submits scores via the microservice (or falls
// back to a direct Firestore write) and shows the live leaderboard. Solo mode
// is fully offline.

// Hooks are aliased to avoid colliding with gameplay.jsx's bare imports —
// every Babel <script type="text/babel"> shares the document's global scope,
// so file-level `const { useState }` would re-declare gameplay's identifier
// and crash the page.
const { useState: useStateApp, useEffect: useEffectApp } = React;

// Service handles — looked up at use-time because Firebase's ESM module
// resolves asynchronously, so caching it during render risks `undefined`.
const FB = () => window.WordraFirebase;
const SS = () => window.WordraStorage;
const I18N = () => window.WordraI18n;
const ANA = () => window.WordraAnalytics;
const SND = () => window.WordraSound;
const HAP = () => window.WordraHaptics;

const FALLBACK_LEADERBOARD = [
  { name: "wordnerd", score: 2840 },
  { name: "swiftfox", score: 2615 },
  { name: "lexi.k",  score: 2390 },
  { name: "tofu_99", score: 1950 },
  { name: "mochi",   score: 1720 },
  { name: "drift",   score: 1480 },
];

function App() {
  const E = window.WordraEngine;
  const ss = SS();
  const K = ss.KEYS;

  // -------- first-launch routing --------
  const [view, setView] = useStateApp(() => {
    const langSet = !!ss.read(K.lang, "");
    if (!langSet) return "langpick";
    if (ss.read(K.onboarded, "") !== "1") return "onboard";
    return "home";
  });

  const [lang,  setLangState] = useStateApp(() => I18N().normalize(ss.read(K.lang, "en")));
  const [theme, setTheme]     = useStateApp(() => ss.read(K.theme, "light"));
  const [settings, setSettings] = useStateApp(() => ({
    sound: true, music: true, haptics: true,
    ...ss.readJSON(K.settings, {}),
    theme: ss.read(K.theme, "light"),
  }));

  // -------- game state --------
  const [mode, setMode] = useStateApp("solo");
  const [seed, setSeed] = useStateApp(() => Math.floor(Math.random() * 1e9));
  const [bestScore, setBestScore] = useStateApp(() => {
    const n = parseInt(ss.read(K.best, "0"), 10);
    return Number.isFinite(n) ? n : 0;
  });
  const [lastResult, setLastResult] = useStateApp(null);
  const [inventory, setInventory] = useStateApp(() =>
    window.loadInventory ? window.loadInventory() : { ...window.DEFAULT_INVENTORY }
  );

  // -------- daily state --------
  const todaySeed = E.todaySeed();
  const [dailyScore, setDailyScore] = useStateApp(() => {
    const raw = ss.read(K.dailyDone, "");
    if (!raw) return 0;
    const [s, sc] = raw.split(":");
    return parseInt(s, 10) === todaySeed ? parseInt(sc, 10) || 0 : 0;
  });
  const [leaderboard, setLeaderboard] = useStateApp(FALLBACK_LEADERBOARD);

  // Analytics: fire screen_view whenever the routed view changes.
  useEffectApp(() => {
    try { ANA() && ANA().screen(view); } catch (_) {}
  }, [view]);

  // theme application + persistence
  useEffectApp(() => {
    document.documentElement.setAttribute("data-theme", theme);
    ss.write(K.theme, theme);
  }, [theme]);
  useEffectApp(() => { setSettings((s) => ({ ...s, theme })); }, [theme]);
  useEffectApp(() => {
    ss.writeJSON(K.settings, settings);
    // Push enable state into the standalone services. They own their own
    // master-volume state but read this every time the user toggles in
    // Settings or the Pause overlay.
    if (SND()) SND().setEnabled(!!settings.sound);
    if (HAP()) HAP().setEnabled(!!settings.haptics);
  }, [settings]);

  const resetProgress = () => {
    try {
      Object.keys(localStorage).forEach((k) => {
        if (k.indexOf("wordra:") === 0) localStorage.removeItem(k);
      });
    } catch (_) {}
    setBestScore(0);
    setDailyScore(0);
    setInventory({ ...window.DEFAULT_INVENTORY });
    setSettings({ sound: true, music: true, haptics: true, theme: "light" });
    setTheme("light");
    setLangState("en");
    setView("langpick");
    try { ANA() && ANA().track("progress_reset"); } catch (_) {}
  };

  // listen to live leaderboard for today's seed (retries until Firebase loads)
  useEffectApp(() => {
    let off = null;
    let cancelled = false;
    const attach = () => {
      const fb = FB();
      if (!fb || !fb.listenDailyLeaderboard) return false;
      off = fb.listenDailyLeaderboard(todaySeed, (rows) => {
        if (cancelled) return;
        if (!rows || rows.length === 0) return; // keep fallback
        const uid = fb.getUid && fb.getUid();
        const annotated = rows.map((r) => ({
          ...r,
          you: r.uid === uid,
          name: r.uid === uid ? "you" : (r.name || "anon"),
        }));
        const merged = annotated.length >= 6
          ? annotated
          : [
              ...annotated,
              ...FALLBACK_LEADERBOARD.filter((f) => !annotated.some((a) => a.name === f.name)),
            ].slice(0, 7);
        setLeaderboard(merged);
      });
      return true;
    };
    if (!attach()) {
      const id = setInterval(() => { if (attach()) clearInterval(id); }, 200);
      return () => { cancelled = true; clearInterval(id); try { off && off(); } catch (_) {} };
    }
    return () => { cancelled = true; try { off && off(); } catch (_) {} };
  }, [todaySeed]);

  // helpers
  const setLang = (l) => {
    const norm = I18N().normalize(l);
    setLangState(norm);
    ss.write(K.lang, norm);
  };
  const updateInventory = (next) => {
    setInventory(next);
    if (window.saveInventory) window.saveInventory(next);
  };

  const startSolo = () => {
    setMode("solo");
    setSeed(Math.floor(Math.random() * 1e9));
    setView("game");
  };
  const startDaily = () => {
    setMode("daily");
    setSeed(todaySeed);
    setView("game");
    try { ANA() && ANA().track("daily_play", { seed: todaySeed }); } catch (_) {}
  };

  const rankOf = (score) => {
    const list = [...leaderboard].map((r) => r.score || 0);
    list.push(score);
    list.sort((a, b) => b - a);
    return list.indexOf(score) + 1;
  };

  const handleEnd = async (result) => {
    if (result.inv) updateInventory(result.inv);
    if (result.score > bestScore) {
      setBestScore(result.score);
      ss.write(K.best, String(result.score));
    }

    // award reward: 1 random item per round, +1 extra if score ≥ 1000
    const items = (window.WORDRA_ITEMS || []);
    if (items.length) {
      const reward = items[Math.floor(Math.random() * items.length)].id;
      const bonusReward = result.score >= 1000 ? items[Math.floor(Math.random() * items.length)].id : null;
      const next = { ...(result.inv || inventory) };
      next[reward] = (next[reward] || 0) + 1;
      if (bonusReward) next[bonusReward] = (next[bonusReward] || 0) + 1;
      updateInventory(next);
      result.reward = reward;
      result.bonusReward = bonusReward;
    }

    let rank = null;
    if (mode === "daily") {
      setDailyScore(result.score);
      ss.write(K.dailyDone, `${todaySeed}:${result.score}`);
      try {
        const top = (result.words || []).slice().sort((a, b) => b.length - a.length)[0] || "";
        const fb = FB();
        if (fb && fb.submitDailyScore) {
          await fb.submitDailyScore({
            seed: todaySeed,
            score: result.score,
            wordCount: (result.words || []).length,
            topWord: top,
            name: ss.getOrCreateName(),
          });
        }
      } catch (err) {
        console.warn("[wordra] daily submit failed:", err);
      }
      rank = rankOf(result.score);
    }

    result.rank = rank;
    setLastResult(result);
    setView("result");
  };

  // -------- screen rendering --------
  return (
    <div className="app-shell">
      {view === "langpick" && (
        <window.WordraLangPicker
          onPick={(l) => {
            setLang(l);
            setView(ss.read(K.onboarded, "") === "1" ? "home" : "onboard");
          }}
        />
      )}

      {view === "onboard" && (
        <window.WordraOnboarding
          lang={lang}
          onDone={() => { ss.write(K.onboarded, "1"); setView("home"); }}
        />
      )}

      {view === "home" && (
        <window.WordraHome
          lang={lang}
          onToggleLang={() => setLang(lang === "en" ? "th" : "en")}
          onPlay={startSolo}
          onDaily={() => setView("daily")}
          onSettings={() => setView("settings")}
          onProfile={() => setView("profile")}
          bestScore={bestScore}
          dailyDone={dailyScore > 0}
          inventory={inventory}
        />
      )}

      {view === "settings" && window.WordraSettings && (
        <window.WordraSettings
          lang={lang}
          settings={settings}
          onChange={(p) => {
            setSettings((s) => ({ ...s, ...p }));
            if (p.theme) setTheme(p.theme);
          }}
          onLang={(l) => setLang(l)}
          onBack={() => setView("home")}
          onResetProgress={resetProgress}
        />
      )}

      {view === "profile" && window.WordraProfile && (
        <window.WordraProfile
          lang={lang}
          stats={null}
          onBack={() => setView("home")}
          onOpenVocab={() => setView("vocab")}
        />
      )}

      {view === "vocab" && window.WordraVocabScreen && (
        <window.WordraVocabScreen
          lang={lang}
          onBack={() => setView("profile")}
        />
      )}

      {view === "game" && (
        <window.WordraGameplay
          seed={seed}
          lang={lang}
          duration={60}
          mode={mode}
          inventory={inventory}
          onInventoryChange={updateInventory}
          onEnd={handleEnd}
          onExit={() => setView("home")}
        />
      )}

      {view === "result" && lastResult && (
        <window.WordraResult
          score={lastResult.score}
          best={Math.max(bestScore, lastResult.score)}
          words={lastResult.words}
          newWords={lastResult.newWords}
          itemsUsed={lastResult.itemsUsed}
          reward={lastResult.reward}
          bonusReward={lastResult.bonusReward}
          lang={lang}
          isDaily={mode === "daily"}
          dailyNo={E.todayLabel()}
          rank={lastResult.rank}
          onReplay={mode === "daily" ? () => setView("daily") : startSolo}
          onHome={() => setView("home")}
        />
      )}

      {view === "daily" && (
        <window.WordraDaily
          lang={lang}
          dailyScore={dailyScore}
          leaderboard={leaderboard}
          onPlay={startDaily}
          onHome={() => setView("home")}
        />
      )}
    </div>
  );
}

// -------- bootstrap --------
function boot() {
  const splash = document.getElementById("splash");
  const EB = window.WordraErrorBoundary;
  const tree = EB ? <EB><App /></EB> : <App />;
  ReactDOM.createRoot(document.getElementById("root")).render(tree);
  if (splash) {
    requestAnimationFrame(() => {
      splash.classList.add("hide");
      setTimeout(() => splash.remove(), 280);
    });
  }
}

window.__bootWordra = boot;
