// Root mount. Renders the routed operator shell (OperatorRoot). The old
// client-side demo login surface has been retired — operators sign in via the
// Microsoft PKCE redirect and customers via /customer/login. A customer session
// reaches ONLY /demo here (rendered with CustomerDemoShell, not the operator
// AppHeader); every other route bounces it to its landing page (see the
// customer-wall effect in OperatorRoot).

const { useState: useStateRoot, useEffect: useEffectRoot } = React;

// ── Shared concerns — both roots need these ─────────────────────────────────

// Read-only (snapshot) mode is decided inside AssemblyLineLive, a sibling tree.
// It broadcasts via window.AL_READONLY + an 'al-readonly-mode' event; we mirror
// it here so the header "Inject Task" button can hide in the read-only viewer.
// Seed from the flag in case the event already fired.
function useReadOnlyMirror() {
  const [readOnly, setReadOnly] = useStateRoot(() =>
    typeof window !== "undefined" && window.AL_READONLY === true);
  useEffectRoot(() => {
    const onMode = (e) => setReadOnly(e.detail?.readOnly === true);
    window.addEventListener("al-readonly-mode", onMode);
    // Defensive: catches the narrow render→effect gap where the event could
    // fire after the lazy initializer ran but before the listener attached.
    if (window.AL_READONLY === true) setReadOnly(true);
    return () => window.removeEventListener("al-readonly-mode", onMode);
  }, []);
  return readOnly;
}

// Demo runner: poll capability + running state; Run/Reset drive run-demo.ts.
function useDemoRunner() {
  const [demoRunner, setDemoRunner] = useStateRoot(false);
  const [demoRunning, setDemoRunning] = useStateRoot(false);
  useEffectRoot(() => {
    let stop = false;
    const tick = () => fetch("/demo/info").then((r) => r.json())
      .then((d) => { if (!stop) { setDemoRunner(!!d.runner); setDemoRunning(!!d.running); } })
      .catch(() => {});
    tick();
    const iv = setInterval(tick, 4000);
    return () => { stop = true; clearInterval(iv); };
  }, []);
  const runDemo = () => { setDemoRunning(true); fetch("/demo/run", { method: "POST" }).then((r) => r.json()).then((d) => setDemoRunning(!!d.running)).catch(() => {}); };
  const resetDemo = () => { setDemoRunning(false); fetch("/demo/reset", { method: "POST" }).catch(() => {}); };
  return { demoRunner, demoRunning, runDemo, resetDemo };
}

// The two header controls that live on the board/demo surface. Rendered through
// OperatorRoot's AppHeader `actions` slot.
const InjectTaskButton = () => (
  <button
    onClick={() => window.dispatchEvent(new CustomEvent("assembly-line:inject-task"))}
    className="flex items-center gap-2 bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-lg font-semibold text-sm transition-colors shadow-md shadow-indigo-600/20 active:scale-95"
  >
    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
      <line x1="12" y1="5" x2="12" y2="19" />
      <line x1="5" y1="12" x2="19" y2="12" />
    </svg>
    Inject Task
  </button>
);

const DemoRunnerButtons = ({ demoRunning, runDemo, resetDemo }) => (
  <div className="flex items-center gap-2">
    <button
      onClick={runDemo}
      disabled={demoRunning}
      className={`flex items-center gap-2 px-4 py-2 rounded-lg font-semibold text-sm transition-colors shadow-md active:scale-95 ${demoRunning ? "bg-emerald-100 text-emerald-700 cursor-default shadow-none" : "bg-emerald-600 hover:bg-emerald-700 text-white shadow-emerald-600/20"}`}
      title="Start the demo — tasks cascade down the line"
    >
      {demoRunning
        ? (<><span className="relative flex w-2 h-2"><span className="absolute inline-flex h-full w-full rounded-full bg-emerald-500 opacity-75 animate-ping" /><span className="relative inline-flex rounded-full h-2 w-2 bg-emerald-500" /></span> Running…</>)
        : (<><svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" aria-hidden><path d="M8 5v14l11-7z" /></svg> Run demo</>)}
    </button>
    <button
      onClick={resetDemo}
      className="flex items-center gap-2 bg-white border border-neutral-300 hover:bg-neutral-100 text-neutral-700 px-3 py-2 rounded-lg font-semibold text-sm transition-colors active:scale-95"
      title="Reset — all tasks back to the start"
    >
      <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden><path d="M3 12a9 9 0 1 0 3-6.7L3 8" /><path d="M3 3v5h5" /></svg>
      Reset
    </button>
  </div>
);

// ── CustomerDemoShell — the ONLY surface a customer session sees in this SPA
//    (/demo). Deliberately NOT the operator AppHeader: no project switcher, no
//    tabs, no settings. Brand mark + title, the demo Run/Reset (only when the
//    server advertises a runner — same gating operators get on /demo), a link
//    back to the customer's landing page, and Sign out. Presentational — the
//    page (OperatorRoot) owns all fetching. ──────────────────────────────────
const CustomerDemoShell = ({ identity, onSignOut, demoRunner, demoRunning, runDemo, resetDemo }) => (
  <div className="min-h-screen bg-neutral-50 font-sans text-neutral-900">
    <header className="bg-white border-b border-neutral-200 px-8 py-4 flex items-center justify-between sticky top-0 z-50">
      <div className="flex items-center gap-3">
        <div className="bg-neutral-900 p-2 rounded-lg text-white shadow-inner">
          {/* Fellow box on a conveyor belt */}
          <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
            <rect x="6.5" y="3" width="11" height="12" rx="1.4" />
            <g transform="translate(8.66 3.43) scale(0.048)" fill="currentColor" stroke="none">
              <path d="M138.12 0V55.41L0 122.09V66.68L138.12 0Z" />
              <path d="M138.12 80.3604V135.8L58.36 174.28V231.41L0 203.25V147.07L138.12 80.3604Z" />
            </g>
            <line x1="2" y1="18.5" x2="22" y2="18.5" />
            <circle cx="6" cy="21" r="1.4" />
            <circle cx="12" cy="21" r="1.4" />
            <circle cx="18" cy="21" r="1.4" />
          </svg>
        </div>
        <div>
          <h1 className="text-xl font-bold tracking-tight leading-none text-neutral-800">Fellow Assembly Line</h1>
          <p className="text-sm font-medium text-neutral-500 mt-1">Live demo</p>
        </div>
      </div>
      <div className="flex items-center gap-3">
        {demoRunner && <DemoRunnerButtons demoRunning={demoRunning} runDemo={runDemo} resetDemo={resetDemo} />}
        <a
          href={identity?.landing ?? "/sales/brief-to-done.html"}
          className="text-sm font-semibold text-neutral-600 hover:text-neutral-900 hover:bg-neutral-100 px-3 py-2 rounded-lg transition-colors"
        >
          ← Back
        </a>
        <button
          onClick={onSignOut}
          className="text-sm font-semibold text-neutral-600 hover:text-neutral-900 hover:bg-neutral-100 px-3 py-2 rounded-lg transition-colors"
        >
          Sign out
        </button>
      </div>
    </header>
    <AssemblyLineApp />
  </div>
);

// ── OperatorRoot — the routed operator shell. useRoute() drives the view:
//    overview → ProjectsOverview · board/demo → AssemblyLineApp · plan/reviews →
//    Placeholder · unknown → navigate("/"). Uses window.AppHeader for the shell.
const Placeholder = ({ title }) => (
  <div className="max-w-3xl mx-auto p-16 text-center">
    <div className="text-lg font-semibold text-neutral-600 mb-1">{title}</div>
    <div className="text-neutral-400">Coming in a later slice.</div>
  </div>
);

const OperatorRoot = () => {
  const route = useRoute(); // { path, name, slug } — router.jsx
  const [signedInUser, setSignedInUser] = useStateRoot(null);
  const [authRequired, setAuthRequired] = useStateRoot(true);
  const [authLoading, setAuthLoading] = useStateRoot(true);
  const [projects, setProjects] = useStateRoot([]);
  const [settingsOpen, setSettingsOpen] = useStateRoot(false);
  const [redirecting, setRedirecting] = useStateRoot(false);
  const readOnly = useReadOnlyMirror();
  const { demoRunner, demoRunning, runDemo, resetDemo } = useDemoRunner();

  // Real auth: whoami → identity + authRequired (false only when the server has
  // no auth configured, i.e. local dev).
  useEffectRoot(() => {
    window.Api.whoami()
      .then(({ identity, authRequired }) => { setSignedInUser(identity); setAuthRequired(authRequired); })
      .finally(() => setAuthLoading(false));
  }, []);

  const authed = !authRequired || signedInUser;
  const isCustomer = signedInUser?.role === "customer";

  // Customer wall, client side: a customer session reaches ONLY /demo in this
  // SPA — its landing page's CTA links here, so /demo must NOT bounce. Every
  // other route bounces to the customer's landing (full-page nav) before any
  // operator UI paints; customers never see the operator shell.
  useEffectRoot(() => {
    if (isCustomer && route.name !== "demo") {
      setRedirecting(true);
      window.location.assign(signedInUser.landing ?? "/sales/brief-to-done.html");
    }
  }, [isCustomer, route.name]);

  // Load the project list once we're past the auth gate. Customers never need
  // it (their only surface is /demo, and the server would 403 the fetch anyway).
  useEffectRoot(() => {
    if (!authed || isCustomer) return;
    window.Api.listProjects()
      .then((ps) => setProjects(Array.isArray(ps) ? ps : []))
      .catch(() => {});
  }, [authed, isCustomer]);

  // Unknown route → home. (matchRoute never marks /demo unknown — redline 1.)
  useEffectRoot(() => {
    if (route.name === "unknown") window.navigate("/");
  }, [route.name]);

  const onSignOut = () => { window.Api.logout().finally(() => setSignedInUser(null)); };

  // currentProject: prefer the fetched record; fall back to a slug-only stub so a
  // deep link renders before the /projects fetch resolves (invariant 4).
  const currentProject = route.slug
    ? (projects.find((p) => p.slug === route.slug)
       || { slug: route.slug, name: route.slug, pmProjectId: null, alProjectId: null })
    : null;

  // Board/demo controls, carried through the header's `actions` slot so they
  // survive the header swap (invariant 3): Inject Task (board + demo, gated
  // !readOnly), and the demo Run/Reset — confined to /demo, never the operator
  // board, and only when the server advertises a demo runner.
  const onBoardSurface = route.name === "board" || route.name === "demo";
  const onDemoSurface = route.name === "demo";
  const actions = onBoardSurface ? (
    <>
      {!readOnly && <InjectTaskButton />}
      {onDemoSurface && demoRunner && <DemoRunnerButtons demoRunning={demoRunning} runDemo={runDemo} resetDemo={resetDemo} />}
    </>
  ) : null;

  if (authLoading || redirecting) return <div className="min-h-screen p-10 text-center text-neutral-400">Loading…</div>;
  if (!authed) return <window.LoginPage />;

  // Customer session: /demo renders the customer chrome (never the operator
  // AppHeader); any other route is mid-bounce (the wall effect above), so hold
  // the loading state until the full-page nav lands.
  if (isCustomer) {
    if (route.name !== "demo") return <div className="min-h-screen p-10 text-center text-neutral-400">Loading…</div>;
    return (
      <CustomerDemoShell
        identity={signedInUser}
        onSignOut={onSignOut}
        demoRunner={demoRunner}
        demoRunning={demoRunning}
        runDemo={runDemo}
        resetDemo={resetDemo}
      />
    );
  }

  let view = null;
  if (route.name === "overview") view = <window.ProjectsOverview projects={projects} />;
  else if (route.name === "board" || route.name === "demo") view = <AssemblyLineApp key={currentProject?.slug} project={currentProject} />;
  else if (route.name === "plan") view = <Placeholder title="Plan & timeline" />;
  else if (route.name === "reviews") view = <Placeholder title="Reviews" />;
  // route.name === "unknown" renders nothing; the effect above redirects to "/".

  return (
    <div className="min-h-screen bg-neutral-50 font-sans text-neutral-900">
      <window.AppHeader
        projects={projects}
        currentProject={currentProject}
        routeName={route.name}
        signedInUser={signedInUser}
        onSignOut={onSignOut}
        onOpenSettings={signedInUser ? () => setSettingsOpen(true) : undefined}
        actions={actions}
      />
      {view}
      {settingsOpen && <window.SettingsPanel onClose={() => setSettingsOpen(false)} />}
    </div>
  );
};

const Root = () => <OperatorRoot />;   // the routed operator shell

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