/* =========================================================================
   TAXR — App shell, router, state + persistence
   ========================================================================= */
const GUEST = { name: "Guest", email: "", paid: false, purchasedModules: [], hints: 3, guest: true };
const STORE = "taxr_state_v1";

function loadState() {
  try { const s = JSON.parse(localStorage.getItem(STORE)); if (s) return s; } catch (e) {}
  return null;
}

/* --------- lightweight overview for modules beyond the built-out Module 1 --------- */
function ModuleOverview({ nav, params, account }) {
  const D = window.TAXR;
  const mod = D.phases.flatMap((p) => p.modules).find((m) => m.id === params.moduleId);
  if (!mod) return null;
  return (
    <div className="wrap" style={{ padding: "30px 32px 80px", maxWidth: 820, margin: "0 auto" }}>
      <button className="row gap-8 fs-14 t-dim" onClick={() => nav("dashboard")} style={{ marginBottom: 22 }}><Icon name="back" size={16} /> All modules</button>
      <div className="row gap-12" style={{ marginBottom: 14 }}>
        <Badge kind="blue">Module {mod.n}</Badge>
        {mod.tag && <span className="mono fs-13 t-dim">{mod.tag}</span>}
        <span className="mono fs-13 t-dim">{mod.lessons} lessons</span>
      </div>
      <h1 className="display" style={{ fontSize: 40, marginBottom: 12 }}>{mod.title}</h1>
      <p className="fs-17 t-muted lh-rel" style={{ maxWidth: 600, marginBottom: 30 }}>{mod.blurb}</p>

      <span className="mono fs-13 t-dim upper" style={{ display: "block", marginBottom: 14 }}>Lessons in this module</span>
      <div className="col gap-8" style={{ marginBottom: 26 }}>
        {mod.topics.map((t, i) => (
          <div key={i} className="card row gap-16" style={{ padding: "15px 18px", alignItems: "center" }}>
            <span style={{ width: 28, height: 28, borderRadius: 8, display: "grid", placeItems: "center", flex: "none", background: "var(--surface-3)", color: "var(--muted)", fontFamily: "var(--mono)", fontSize: 12 }}>{i + 1}</span>
            <span className="fs-16" style={{ flex: 1 }}>{t}</span>
            <Icon name="chev" size={16} style={{ color: "var(--dim)" }} />
          </div>
        ))}
      </div>

      <Pip tone="tip" title="Same format as Module 1">
        Each lesson here reads, tests and drills exactly like Module 1 — short lesson, 5-question check, then the {mod.lessons}-lesson module test and a flashcard deck. Jump into Module 1 to feel the full flow end-to-end.
      </Pip>
      <div className="row gap-12" style={{ marginTop: 22 }}>
        <Button arrow onClick={() => nav("lesson", { lessonId: "l1-1" })}>Preview the Module 1 flow</Button>
        <Button variant="ghost" onClick={() => nav("flashcards", { moduleId: "m1" })}>Try flashcards</Button>
      </div>
    </div>
  );
}

/* ----------------------------------------------------------- app-shell nav */
function AppNav({ view, account, progress, nav, onMenu, openShop, overall, dueCount = 0 }) {
  const [menu, setMenu] = useState(false);
  return (
    <header style={{ position: "sticky", top: 0, zIndex: 60, background: "var(--nav-bg)", backdropFilter: "blur(12px)", borderBottom: "1px solid var(--line)" }}>
      <div className="row spread" style={{ height: 64, padding: "0 32px", maxWidth: 1280, margin: "0 auto" }}>
        <div className="row gap-24">
          <a href="https://waddl3.com" title="Back to Waddl3" className="hide-mobile row gap-6" style={{ alignItems: "center", color: "var(--dim)", fontSize: 13, textDecoration: "none", transition: "color .15s" }}
            onMouseEnter={(e) => e.currentTarget.style.color = "var(--muted)"}
            onMouseLeave={(e) => e.currentTarget.style.color = "var(--dim)"}>
            <span style={{ fontSize: 16 }}>🐧</span>
          </a>
          <button onClick={() => nav("dashboard")}><Logo size={20} /></button>
          <button className="row gap-8 fs-14 hide-mobile" onClick={() => nav("dashboard")} style={{ color: view === "dashboard" ? "var(--text)" : "var(--muted)" }}>
            <Icon name="grid" size={16} /> My track
          </button>
          <button className="row gap-8 fs-14 hide-mobile" onClick={() => nav("review")} style={{ color: view === "review" ? "var(--text)" : "var(--muted)" }}>
            <Icon name="spark" size={16} /> Review
            {dueCount > 0 && <span className="mono" style={{ fontSize: 11, fontWeight: 600, padding: "1px 7px", borderRadius: 999, background: "var(--amber-soft)", color: "var(--amber)", border: "1px solid rgba(231,179,92,0.4)" }}>{dueCount}</span>}
          </button>
        </div>
        <div className="row gap-16">
          {overall > 0 && (
            <div className="row gap-10 hide-mobile" style={{ alignItems: "center" }}>
              <div style={{ width: 110 }}><Progress value={overall} green={overall === 100} thin /></div>
              <span className="mono fs-13 t-dim">{overall}%</span>
            </div>
          )}
          <Fish count={account.hints} onClick={openShop} compact />
          <ThemeSwitcher />
          {!account.paid && <Button size="sm" variant="ghost" onClick={() => nav("checkout", { plan: "full" })}><Icon name="spark" size={14} style={{ color: "var(--amber)" }} /> Unlock all</Button>}
          <div style={{ position: "relative" }}>
            <button onClick={() => setMenu((m) => !m)} className="row gap-8" style={{ padding: "6px 8px 6px 12px", borderRadius: 999, border: "1px solid var(--line)" }}>
              <span style={{ width: 26, height: 26, borderRadius: "50%", background: "var(--blue-soft)", color: "var(--blue-bright)", display: "grid", placeItems: "center" }}><Icon name="user" size={15} /></span>
              <Icon name="chevd" size={14} style={{ color: "var(--dim)" }} />
            </button>
            {menu && (
              <>
                <div onClick={() => setMenu(false)} style={{ position: "fixed", inset: 0, zIndex: 1 }} />
                <div className="card pop" style={{ position: "absolute", right: 0, top: 46, width: 230, padding: 8, zIndex: 2, boxShadow: "var(--shadow-lg)" }}>
                  <div style={{ padding: "10px 12px" }}>
                    <div className="fs-14" style={{ fontWeight: 600 }}>{account.name}</div>
                    <div className="fs-13 t-dim">{account.guest ? "Guest · not signed in" : account.email}</div>
                    <Badge kind={account.paid ? "solid-green" : "lock"} style={{ marginTop: 8 }}>{account.paid ? "Full course" : "Free preview"}</Badge>
                  </div>
                  <div className="hr" style={{ margin: "6px 0" }} />
                  {account.guest && <button className="row gap-12" style={{ padding: "10px 12px", width: "100%", color: "var(--text)", fontSize: 14 }} onClick={() => { setMenu(false); nav("auth", { mode: "signup" }); }}><Icon name="user" size={16} /> Create account</button>}
                  <button className="row gap-12" style={{ padding: "10px 12px", width: "100%", color: "var(--muted)", fontSize: 14 }} onClick={() => { setMenu(false); openShop(); }}><Icon name="fish" size={16} /> Buy hints</button>
                  <button className="row gap-12" style={{ padding: "10px 12px", width: "100%", color: "var(--muted)", fontSize: 14 }} onClick={() => { setMenu(false); nav("certificate"); }}><Icon name="trophy" size={16} /> My certificate</button>
                  <button className="row gap-12" style={{ padding: "10px 12px", width: "100%", color: "var(--muted)", fontSize: 14 }} onClick={() => { setMenu(false); onMenu("reset"); }}><Icon name="back" size={16} /> Reset demo</button>
                  <button className="row gap-12" style={{ padding: "10px 12px", width: "100%", color: "var(--muted)", fontSize: 14 }} onClick={() => { setMenu(false); onMenu("signout"); }}><Icon name="x" size={16} /> Sign out</button>
                </div>
              </>
            )}
          </div>
        </div>
      </div>
    </header>
  );
}

/* --------- spaced repetition (Leitner) — days until an item is due, by box --------- */
const REVIEW_INT = { 1: 0, 2: 1, 3: 3, 4: 7, 5: 21 };
const DAY = 86400000;

/* --------------------------------------------------------------------- App */
function App() {
  const saved = loadState();
  const [view, setView] = useState(saved ? saved.view : "landing");
  const [params, setParams] = useState(saved ? saved.params || {} : {});
  const [account, setAccount] = useState(saved ? saved.account : GUEST);
  const [progress, setProgress] = useState(saved ? { lessons: {}, tests: {}, review: {}, ...saved.progress } : { lessons: {}, tests: {}, review: {} });
  const [shop, setShop] = useState(false);
  const [taxrActivating, setTaxrActivating] = useState(false);

  // persist
  useEffect(() => {
    localStorage.setItem(STORE, JSON.stringify({ view, params, account, progress }));
  }, [view, params, account, progress]);

  // apply saved theme on load
  useEffect(() => { try { applyTheme(localStorage.getItem("taxr_theme") || "dark"); } catch (e) {} }, []);

  useEffect(() => { window.scrollTo(0, 0); }, [view, params]);

  // handle Creem return URL — ?taxr_paid=full | mod_m1 | hints_fish25
  // Hints apply immediately (low risk). Module/course unlocks are verified via Firestore
  // so that this URL param cannot be forged to unlock paid content for free.
  useEffect(() => {
    const sp = new URLSearchParams(window.location.search);
    const paid = sp.get("taxr_paid");
    if (!paid) return;
    window.history.replaceState({}, "", window.location.pathname);

    if (paid.startsWith("hints_")) {
      onBuyHints(paid.slice(6));
      nav("dashboard");
      return;
    }

    // For paid module/course: poll Firestore until the webhook write lands
    const firebaseUser = window.taxrAuth?.currentUser;
    if (!firebaseUser || !window.taxrDb) {
      nav("dashboard");
      return;
    }

    function purchaseRecorded(data) {
      if (!data) return false;
      if (paid === "full") return !!data.paid;
      if (paid.startsWith("bundle_")) {
        const bundleMods = window.TAXR?.pricing?.bundles?.[paid.slice(7)]?.modules || [];
        return bundleMods.every((m) => (data.purchasedModules || []).includes(m));
      }
      if (paid.startsWith("mod_")) return (data.purchasedModules || []).includes(paid.slice(4));
      return false;
    }

    setTaxrActivating(true);
    let attempts = 0;
    const poll = setInterval(async () => {
      attempts++;
      try {
        const snap = await window.taxrDb.collection("taxr_users").doc(firebaseUser.uid).get();
        const data = snap.data();
        if (purchaseRecorded(data)) {
          clearInterval(poll);
          setAccount((a) => ({
            ...a,
            paid: data.paid || a.paid,
            purchasedModules: [...new Set([...(a.purchasedModules || []), ...(data.purchasedModules || [])])],
          }));
          setTaxrActivating(false);
          nav("dashboard");
          return;
        }
      } catch {}
      if (attempts >= 10) {
        clearInterval(poll);
        setTaxrActivating(false);
        nav("dashboard");
      }
    }, 3000);
    return () => clearInterval(poll);
  }, []);

  // sync with Waddl3 ID — if user is already signed in via Firebase, apply it
  // Also reads taxr_users/{uid} from Firestore to restore server-recorded purchases.
  useEffect(() => {
    if (!window.taxrAuth) return;
    const unsub = window.taxrAuth.onAuthStateChanged(async (firebaseUser) => {
      if (firebaseUser) {
        setAccount((a) => ({
          ...a,
          name:  firebaseUser.displayName || firebaseUser.email.split("@")[0],
          email: firebaseUser.email,
          uid:   firebaseUser.uid,
          guest: false,
        }));
        if (window.taxrDb) {
          try {
            const snap = await window.taxrDb.collection("taxr_users").doc(firebaseUser.uid).get();
            if (snap.exists) {
              const data = snap.data();
              setAccount((a) => ({
                ...a,
                paid: data.paid || a.paid,
                purchasedModules: [...new Set([...(a.purchasedModules || []), ...(data.purchasedModules || [])])],
              }));
            }
          } catch (e) {
            console.warn("Taxr: Firestore purchase sync failed", e);
          }
        }
      }
    });
    return () => unsub();
  }, []);

  function nav(v, p = {}) { setView(v); setParams(p); }
  function onAuth(user) { setAccount((a) => ({ ...a, ...user, guest: false })); }
  function finishOnboarding() { setAccount((a) => ({ ...a, onboarded: true })); nav("lesson", { lessonId: "l1-1" }); }
  function onComplete(lessonId) { setProgress((p) => ({ ...p, lessons: { ...p.lessons, [lessonId]: true } })); }
  function onTestComplete(moduleId, score) {
    setProgress((p) => ({ ...p, tests: { ...p.tests, [moduleId]: Math.max(score, (p.tests || {})[moduleId] || 0) } }));
  }
  // spaced repetition: missed quiz Qs / flashcards get enrolled; correct reviews graduate up a box
  function recordReview(item) {
    setProgress((p) => {
      const review = { ...(p.review || {}) };
      const ex = review[item.id];
      if (item.correct) {
        if (!ex) return p; // never enrolled — don't clutter the review deck
        const box = Math.min((ex.box || 1) + 1, 6);
        if (box >= 6) { delete review[item.id]; } // mastered — graduate out
        else review[item.id] = { ...ex, box, due: Date.now() + (REVIEW_INT[box] || 21) * DAY, last: "right", payload: item.payload || ex.payload, type: item.type || ex.type };
      } else {
        review[item.id] = { type: item.type, payload: item.payload, box: 1, due: Date.now(), last: "wrong", since: ex ? ex.since : Date.now() };
      }
      return { ...p, review };
    });
  }
  function onPurchase(upd) {
    setAccount((a) => {
      if (upd.paid) return { ...a, paid: true, hints: a.hints + 10, guest: false };
      if (upd.bundle) {
        const bundleDef = window.TAXR.pricing.bundles[upd.bundle];
        const newMods = bundleDef ? bundleDef.modules : [];
        return { ...a, purchasedModules: [...new Set([...(a.purchasedModules || []), ...newMods])] };
      }
      if (upd.module) return { ...a, purchasedModules: [...new Set([...(a.purchasedModules || []), upd.module])] };
      return a;
    });
  }
  function onBuyHints(packId) {
    const pack = window.TAXR.pricing.hintPacks.find((h) => h.id === packId);
    setAccount((a) => ({ ...a, hints: a.hints + (pack ? pack.count : 0) }));
  }
  function spendHint() { setAccount((a) => ({ ...a, hints: Math.max(0, a.hints - 1) })); }
  function onMenu(action) {
    if (action === "reset") { localStorage.removeItem(STORE); setAccount(GUEST); setProgress({ lessons: {}, tests: {}, review: {} }); nav("landing"); }
    if (action === "signout") {
      if (window.taxrAuth) window.taxrAuth.signOut().catch(() => {});
      setAccount(GUEST);
      nav("landing");
    }
  }

  // review items currently due
  const reviewMap = progress.review || {};
  const dueCount = Object.values(reviewMap).filter((r) => r && r.due <= Date.now()).length;

  // overall progress for nav
  let done = 0, total = 0;
  window.TAXR.phases.forEach((p) => p.modules.forEach((m) => {
    const s = window.moduleState(m, account, progress); total += s.total; done += s.lessonsDone;
  }));
  const overall = total ? Math.round((done / total) * 100) : 0;

  const isMarketing = view === "landing" || view === "auth" || view === "product" || view === "onboarding";

  let page;
  switch (view) {
    case "landing":    page = <Landing nav={nav} />; break;
    case "product":    page = <Product nav={nav} />; break;
    case "onboarding": page = <Onboarding nav={nav} onFinish={finishOnboarding} />; break;
    case "auth":       page = <Auth nav={nav} params={params} account={account} onAuth={onAuth} />; break;
    case "dashboard":  page = <Dashboard nav={nav} account={account} progress={progress} dueCount={dueCount} />; break;
    case "lesson":     page = <Lesson nav={nav} params={params} account={account} progress={progress} onComplete={onComplete} />; break;
    case "module":     page = <ModuleOverview nav={nav} params={params} account={account} />; break;
    case "quiz":       page = <Quiz nav={nav} params={params} account={account} progress={progress} onTestComplete={onTestComplete} hints={account.hints} spendHint={spendHint} buyHints={() => setShop(true)} recordReview={recordReview} />; break;
    case "flashcards": page = <Flashcards nav={nav} params={params} account={account} recordReview={recordReview} />; break;
    case "review":     page = <Review nav={nav} account={account} progress={progress} recordReview={recordReview} />; break;
    case "paywall":    page = <Paywall nav={nav} params={params} account={account} progress={progress} />; break;
    case "checkout":   page = <Checkout nav={nav} params={params} account={account} onPurchase={onPurchase} onBuyHints={onBuyHints} />; break;
    case "certificate": page = <Certificate nav={nav} account={account} progress={progress} />; break;
    default:           page = <Landing nav={nav} />;
  }

  if (taxrActivating) {
    return (
      <div style={{ position: "fixed", inset: 0, zIndex: 9999, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", background: "var(--bg)", gap: 16 }}>
        <div style={{ width: 48, height: 48, border: "3px solid var(--line)", borderTopColor: "var(--amber)", borderRadius: "50%", animation: "spin 0.9s linear infinite" }} />
        <p style={{ color: "var(--amber)", fontFamily: "var(--serif)", fontWeight: 600, fontSize: 18 }}>Confirming your purchase…</p>
        <p style={{ color: "var(--muted)", fontSize: 14 }}>Syncing your access — just a moment</p>
        <style>{`@keyframes spin { to { transform: rotate(360deg) } }`}</style>
      </div>
    );
  }

  return (
    <div style={{ background: "var(--bg)", color: "var(--text)", minHeight: "100vh", transition: "color .3s ease" }}>
      {!isMarketing && <AppNav view={view} account={account} progress={progress} nav={nav} onMenu={onMenu} openShop={() => setShop(true)} overall={overall} dueCount={dueCount} />}
      {page}
      {shop && <HintShop onClose={() => setShop(false)} nav={nav} />}
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
