/* ==================================================================
   App root — orchestrates screens + tweaks
   ------------------------------------------------------------------
   Two columns: the left sidebar (brand + grouped nav) beside a main
   column holding the thin top bar and the content. Below 1024px the
   sidebar moves into a drawer opened from the top bar. Section →
   screen mapping lives in shell.jsx's NAV_SECTIONS, which the sidebar,
   top bar and this router all read, so adding a screen is one edit
   there plus a case below.
   ================================================================== */

const KTopbar = window.AppUI.CockpitTopbar;
const KSidebar = window.AppUI.CockpitSidebar;
const KRadialNav = window.AppUI.CockpitRadialNav;
const KIcon = window.AppUI.Icon;

// `accent: ""` means "use --accent from theme.css". Picking a swatch in the
// Tweaks panel overrides it at runtime for this browser only.
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "",
  "density": "comfortable"
}/*EDITMODE-END*/;

// Landing screen. `?screen=` is how the installed app's home-screen shortcuts
// (manifest.webmanifest) open straight into Staff Attendance / Finance
// instead of always dropping the user on the dashboard. Unknown values fall
// through to the dashboard rather than rendering an empty router default.
const KNOWN_SCREENS = new Set([
  "dashboard", "academics", "staff-attendance",
  "student-attendance", "holidays",
  "parents-overview", "assessment-overview", "finance", "library", "online-tests",
  "evaluate", "report", "answer-key", "doubts", "ai-review", "notifications",
  "teachers", "students", "parents", "announcements", "personnel", "taxonomy",
  "chapters", "topics", "exams", "parent-complaints",
  "sheet-builder", "setup",
]);
const initialScreen = () => {
  try {
    const want = new URLSearchParams(window.location.search).get("screen");
    if (want && KNOWN_SCREENS.has(want)) return want;
    // Guided setup (screen-setup.jsx): while the school is not onboarded, open
    // it once per browser session; the dashboard banner resumes it after that.
    const ob = window.APP.ONBOARDING;
    const claimed = new URLSearchParams(window.location.search).get("claimed") === "1";
    if (ob && ob.applicable && !ob.onboarded_at && !claimed && sessionStorage.getItem("setup.autoshown") !== "1") {
      sessionStorage.setItem("setup.autoshown", "1");
      return "setup";
    }
  } catch { /* no URL access — fall through */ }
  return "dashboard";
};

const App = () => {
  const [screen, setRawScreen] = useState(initialScreen);
  const [pickerOpen, setPickerOpen] = useState(false);
  const [evalTest, setEvalTest] = useState(null);
  const [authoringMeta, setAuthoringMeta] = useState(null);
  const [authoringInitial, setAuthoringInitial] = useState(null);
  const [pendingSaveHandler, setPendingSaveHandler] = useState(null);
  const [tweaks, setTweak] = (typeof useTweaks === "function") ? useTweaks(TWEAK_DEFAULTS) : [TWEAK_DEFAULTS, () => {}];

  // Intercept screen change: opening "evaluate" without a chosen test pops the picker first.
  // If the library/upload-sheets flow set window.APP.EVAL_CONTEXT first, honour it directly.
  const setScreen = (next) => {
    // A paid module this school lacks opens its locked screen (shell.jsx), not the picker.
    if (next === "evaluate" && window.AppUI.featLockFor?.("evaluate")) { setRawScreen(next); window.scrollTo({ top: 0, behavior: "instant" }); return; }
    if (next === "evaluate") {
      const ctx = window.APP.EVAL_CONTEXT;
      if (ctx?.test) {
        setEvalTest(ctx.test);
        setRawScreen("evaluate");
        return;
      }
      if (!evalTest) { setPickerOpen(true); return; }
    }
    setRawScreen(next);
    // Landing on a new screen should start at the top of it — without this a
    // jump from the foot of a long list opens the next screen mid-page.
    window.scrollTo({ top: 0, behavior: "instant" });
  };

  useEffect(() => {
    if (tweaks.accent) document.documentElement.style.setProperty('--accent', tweaks.accent);
    else document.documentElement.style.removeProperty('--accent');
    const density = tweaks.density;
    document.body.style.fontSize = density === "compact" ? "12px" : density === "spacious" ? "14px" : "13px";
  }, [tweaks]);

  // Cross-component navigation hook. Used by the notifications panel (in
  // shell.jsx) to jump to the submissions view for a specific test without
  // threading setScreen through every component.
  useEffect(() => {
    window.APP = window.APP || {};
    window.APP.navigate = (target, opts = {}) => {
      if (target === "evaluate" && opts.testDisplayId) {
        const test = (window.APP.TESTS || []).find(t => t.id === opts.testDisplayId);
        if (test) {
          window.APP.EVAL_CONTEXT = { test };
          setEvalTest(test);
          setRawScreen("evaluate");
          return;
        }
        setPickerOpen(true);
        return;
      }
      if (target === "doubts" && opts.doubtId) {
        // Preselect a specific thread when arriving from a notification.
        window.APP.DOUBTS_CONTEXT = { doubtId: opts.doubtId, tab: opts.tab || "open" };
      }
      setScreen(target);
    };
    return () => { if (window.APP) delete window.APP.navigate; };
  }, [evalTest]);

  const Screen = () => {
    // Paid add-on not unlocked for this school: the locked screen instead of the module.
    const lockedFeature = window.AppUI.featLockFor?.(screen);
    if (lockedFeature) return <window.AppUI.FeatLockedScreen feature={lockedFeature}/>;
    switch(screen) {
      /* ---- Cockpit overview screens ---- */
      case "dashboard":
        return typeof window.CockpitDashboard !== "undefined"
          ? <window.CockpitDashboard setScreen={setScreen}/>
          : <Placeholder name="Dashboard" desc="Module not loaded — check screen-cockpit-dashboard.jsx is included in index.html."/>;
      case "academics":
        return typeof window.CockpitAcademics !== "undefined"
          ? <window.CockpitAcademics setScreen={setScreen}/>
          : <Placeholder name="Academics" desc="Module not loaded — check screen-cockpit-academics.jsx is included in index.html."/>;
      case "staff-attendance":
        return typeof window.CockpitStaffAttendance !== "undefined"
          ? <window.CockpitStaffAttendance setScreen={setScreen}/>
          : <Placeholder name="Staff Attendance" desc="Module not loaded — check screen-cockpit-staff-attendance.jsx is included in index.html."/>;
      case "holidays":
        return typeof window.CockpitHolidays !== "undefined"
          ? <window.CockpitHolidays setScreen={setScreen}/>
          : <Placeholder name="Holidays" desc="Module not loaded — check screen-cockpit-holidays.jsx is included in index.html."/>;
      case "student-attendance":
        return typeof window.CockpitStudentAttendance !== "undefined"
          ? <window.CockpitStudentAttendance setScreen={setScreen}/>
          : <Placeholder name="Student Attendance" desc="Module not loaded — check screen-cockpit-student-attendance.jsx is included in index.html."/>;
      case "parents-overview":
        return typeof window.CockpitParents !== "undefined"
          ? <window.CockpitParents setScreen={setScreen}/>
          : <Placeholder name="Parents" desc="Module not loaded — check screen-cockpit-parents.jsx is included in index.html."/>;
      case "assessment-overview":
        return typeof window.CockpitAssessment !== "undefined"
          ? <window.CockpitAssessment setScreen={setScreen}/>
          : <Placeholder name="Assessment" desc="Module not loaded — check screen-cockpit-assessment.jsx is included in index.html."/>;
      case "finance":
        return typeof window.CockpitFinance !== "undefined"
          ? <window.CockpitFinance setScreen={setScreen}/>
          : <Placeholder name="Finance" desc="Module not loaded — check screen-cockpit-finance.jsx is included in index.html."/>;

      /* ---- Existing deep screens ---- */
      case "library":   return <window.TestLibrary setScreen={setScreen}
        onOpenManual={(meta, saveHandler, initial) => { setAuthoringMeta(meta); setPendingSaveHandler(() => saveHandler); setAuthoringInitial(initial || null); setRawScreen("manual"); }}/>;
      case "manual":    return <window.ManualAuthoring meta={authoringMeta} initialSections={authoringInitial}
        onSave={async (t) => {
          if (pendingSaveHandler) await pendingSaveHandler(t);
          setAuthoringMeta(null); setAuthoringInitial(null); setRawScreen("library");
        }}
        onCancel={() => { setAuthoringMeta(null); setAuthoringInitial(null); setRawScreen("library"); }}/>;
      case "report":    return <window.ClassReports setScreen={setScreen}/>;
      case "evaluate":  return <window.PaperEvaluation initialTest={evalTest}
        onChangeTest={() => { setEvalTest(null); setPickerOpen(true); }}
        setScreen={setScreen}/>;
      case "answer-key":
        return typeof window.AnswerKeyAuthoring !== "undefined"
          ? <window.AnswerKeyAuthoring setScreen={setScreen}/>
          : <Placeholder name="Model Answer Keys" desc="Module not loaded — check screen-answer-key.jsx is included in index.html."/>;
      case "online-tests":
        return typeof window.OnlineTestsScreen !== "undefined"
          ? <window.OnlineTestsScreen setScreen={setScreen}/>
          : <Placeholder name="Online Tests" desc="Module not loaded — check screen-online-tests.jsx is included in index.html."/>;
      case "teachers":
        return typeof window.TeachersScreen !== "undefined"
          ? <window.TeachersScreen/>
          : <Placeholder name="Teachers" desc="Module not loaded — check screen-admin.jsx is included in index.html."/>;
      case "taxonomy":
        return typeof window.TaxonomyScreen !== "undefined"
          ? <window.TaxonomyScreen/>
          : <Placeholder name="Classes & Subjects" desc="Module not loaded — check screen-admin-taxonomy.jsx is included in index.html."/>;
      case "chapters":
        return typeof window.ChaptersScreen !== "undefined"
          ? <window.ChaptersScreen/>
          : <Placeholder name="Chapters" desc="Module not loaded — check screen-admin-chapters.jsx is included in index.html."/>;
      case "topics":
        return typeof window.TopicsScreen !== "undefined"
          ? <window.TopicsScreen/>
          : <Placeholder name="Topics" desc="Module not loaded — check screen-admin-topics.jsx is included in index.html."/>;
      case "students":
        return typeof window.StudentsScreen !== "undefined"
          ? <window.StudentsScreen/>
          : <Placeholder name="Students" desc="Module not loaded — check screen-admin-students.jsx is included in index.html."/>;
      case "parents":
        return typeof window.AdminParentsScreen !== "undefined"
          ? <window.AdminParentsScreen/>
          : <Placeholder name="Parents" desc="Module not loaded — check screen-admin-parents.jsx is included in index.html."/>;
      case "announcements":
        return typeof window.AdminAnnouncementsScreen !== "undefined"
          ? <window.AdminAnnouncementsScreen/>
          : <Placeholder name="Announcements" desc="Module not loaded — check screen-admin-announcements.jsx is included in index.html."/>;
      case "doubts":
        return typeof window.DoubtsScreen !== "undefined"
          ? <window.DoubtsScreen/>
          : <Placeholder name="Doubts" desc="Module not loaded — check screen-doubts.jsx is included in index.html."/>;
      case "ai-review":
        return typeof window.AiReviewScreen !== "undefined"
          ? <window.AiReviewScreen/>
          : <Placeholder name="AI Test Review" desc="Module not loaded — check screen-ai-review.jsx is included in index.html."/>;
      case "notifications":
        return typeof window.NotificationsScreen !== "undefined"
          ? <window.NotificationsScreen/>
          : <Placeholder name="Notifications" desc="Module not loaded — check screen-notifications.jsx is included in index.html."/>;
      case "exams":
        return typeof window.ExamsScreen !== "undefined"
          ? <window.ExamsScreen/>
          : <Placeholder name="Examinations" desc="Module not loaded — check screen-exams.jsx is included in index.html."/>;
      case "parent-complaints":
        return typeof window.ParentComplaintsScreen !== "undefined"
          ? <window.ParentComplaintsScreen/>
          : <Placeholder name="Parent Complaints" desc="Module not loaded — check screen-parent-complaints.jsx is included in index.html."/>;
      case "personnel":
        return typeof window.PersonnelScreen !== "undefined"
          ? <window.PersonnelScreen/>
          : <Placeholder name="Personnel" desc="Module not loaded — check screen-personnel.jsx is included in index.html."/>;
      case "setup":
        return typeof window.SetupScreen !== "undefined"
          ? <window.SetupScreen setScreen={setScreen}/>
          : <Placeholder name="Guided setup" desc="Module not loaded — check screen-setup.jsx is included in index.html."/>;
      case "sheet-builder":
        return typeof window.SheetBuilderScreen !== "undefined"
          ? <window.SheetBuilderScreen setScreen={setScreen}/>
          : <Placeholder name="Sheet Builder" desc="Module not loaded — check screen-sheet-builder.jsx is included in index.html."/>;
      default: return <Placeholder name={screen}/>;
    }
  };

  return (
    <>
      <div className="app">
        <KSidebar screen={screen} setScreen={setScreen}/>
        <div className="main">
          <KTopbar screen={screen} setScreen={setScreen}/>
          {typeof window.TestPickerModal !== "undefined" && (
            <window.TestPickerModal open={pickerOpen} onClose={()=>setPickerOpen(false)}
              onPick={(t) => { setEvalTest(t); setPickerOpen(false); setRawScreen("evaluate"); }}/>
          )}
          <div className="content">
            {screen === "dashboard" && typeof window.SetupResumeBanner !== "undefined" && <window.SetupResumeBanner setScreen={setScreen}/>}
            <Screen/>
          </div>
        </div>
        {/* Hidden above 760px by CSS — see .cx-radialnav. */}
        <KRadialNav screen={screen} setScreen={setScreen}/>
      </div>

      {/* Lives outside the router: a "question reported" notification can fire
          from any screen, and the modal listens on a window event. */}
      {typeof window.AppUI?.EditQuestionModal !== "undefined" && <window.AppUI.EditQuestionModal/>}

      {/* A prospect demo just claimed (?claimed=1): keep the sample data or start clean. */}
      {typeof window.SetupClaimedModal !== "undefined" && <window.SetupClaimedModal setScreen={setScreen}/>}

      {typeof TweaksPanel !== "undefined" && (
        <TweaksPanel title="Tweaks">
          <TweakSection title="Visual">
            <TweakColor label="Accent" value={tweaks.accent}
              options={["var(--primary)", "var(--chart-1)", "var(--chart-2)", "var(--chart-3)", "var(--chart-4)"]}
              onChange={v => setTweak("accent", v)}/>
            <TweakRadio label="Density" value={tweaks.density}
              options={[
                { label:"Compact", value:"compact" },
                { label:"Comfy", value:"comfortable" },
                { label:"Spacious", value:"spacious" },
              ]}
              onChange={v => setTweak("density", v)}/>
          </TweakSection>
          <TweakSection title="Navigate">
            <TweakSelect label="Jump to" value={screen}
              options={[
                { label:"Dashboard", value:"dashboard" },
                { label:"Academics", value:"academics" },
                { label:"Assessment", value:"assessment-overview" },
                { label:"Parents", value:"parents-overview" },
                { label:"Finance", value:"finance" },
                { label:"Test Library", value:"library" },
              ]}
              onChange={setScreen}/>
          </TweakSection>
        </TweaksPanel>
      )}
    </>
  );
};

const Placeholder = ({ name, desc }) => (
  <div className="cx-page">
    <window.AppUI.EmptyState card icon="alertCircle" title={name} hint={desc || "Coming soon."}/>
  </div>
);

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <div className="cx-page">
    <div className="cx-card"><div className="ui-empty"><div className="ui-empty-hint">Loading…</div></div></div>
  </div>,
);

// Take down the inline boot screen from index.html. Called after the first
// real render — either the app or the login form — so the user never sees a
// blank page between "scripts finished" and "something is on screen".
//
// The rAF matters: root.render() only SCHEDULES work, so removing the overlay
// on the same tick reveals an empty #root for a frame. Waiting one frame lets
// React commit first. The timeout is a backstop — if bootstrap throws in a way
// that never reaches a render, the boot screen must still come down rather
// than trapping the user behind it forever.
let bootDismissed = false;
function dismissBoot() {
  if (bootDismissed) return;
  bootDismissed = true;
  const el = document.getElementById("cx-boot");
  if (!el) return;
  requestAnimationFrame(() => {
    el.classList.add("gone");
    setTimeout(() => el.remove(), 320);
  });
}
setTimeout(dismissBoot, 15000);

// Which school this host serves (/api/tenant-info): its logo for the brand
// mark, and — for a prospect demo — the demo banner and a noindex meta tag on
// every screen, the login screen included (docs/SELF_SERVE.md).
const tenantInfoReady = fetch(`${window.AppApi.base}/tenant-info`, { cache: "no-store" })
  .then((r) => (r.ok ? r.json() : null))
  .then((t) => {
    window.APP.TENANT = t || null;
    if (!t) return;
    if (t.logo_url && window.BRAND) window.BRAND.logoUrl = t.logo_url;
    if (t.kind === "prospect_demo") {
      if (!document.querySelector('meta[name="robots"]')) {
        const m = document.createElement("meta");
        m.name = "robots"; m.content = "noindex, nofollow";
        document.head.appendChild(m);
      }
      if (!document.getElementById("demo-banner")) {
        const b = document.createElement("div");
        b.id = "demo-banner"; b.setAttribute("role", "note"); b.setAttribute("data-demo-banner", "");
        b.style.cssText = "position:relative;z-index:300;padding:7px 16px;text-align:center;font:500 13px/1.4 var(--font-sans,system-ui);background:#fef3c7;color:#78350f;border-bottom:1px solid #fcd34d";
        const strong = document.createElement("strong");
        strong.textContent = t.prospect_name || "this school";
        b.append("Demo prepared for ", strong, " by Craft & Code. Not an official school site.");
        document.body.insertBefore(b, document.getElementById("root"));
      }
    }
  })
  .catch(() => { window.APP.TENANT = null; });

async function renderRoot() {
  try { await window.bootstrapApp(); }
  catch (e) { console.error("[bootstrap] failed:", e); }
  await tenantInfoReady;
  // Which paid add-ons this school has (GET /api/features; shell.jsx).
  if (window.AppUI.featReady) await window.AppUI.featReady;
  // Guided setup status (admins of a self-serve school only; null elsewhere).
  if (!window.APP.NEEDS_LOGIN && window.APP.CURRENT_USER?.role === "admin") {
    window.APP.ONBOARDING = await window.AppApi.get("/admin/onboarding").catch(() => null);
  }
  if (window.APP.NEEDS_LOGIN) {
    root.render(<window.CockpitLogin onLoggedIn={renderRoot}/>);
  } else {
    root.render(<App/>);
  }
  dismissBoot();
}

renderRoot();
