// CABL Procurement Lab — root app + state machine.
//
// Procurement-only. Authenticated. Single product, single flow:
//   login / signup → workspace → chat → plan
// Settings is a side route accessible from the top bar at any time.

const { useState: useStateApp, useEffect: useEffectApp } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#E63946",
  "displayFont": "Newsreader",
  "density": "comfortable",
  "showWatermark": false
}/*EDITMODE-END*/;

const APP_IS_DEMO = new URLSearchParams(window.location.search).has("demo");
const ONBOARDING_PREVIEW = new URLSearchParams(window.location.search).get("onboarding");
const ONBOARDING_PREVIEW_ENABLED =
  APP_IS_DEMO && ["self", "company"].includes(String(ONBOARDING_PREVIEW || "").toLowerCase());

// Session-cost accumulator. Lives on window so chat / app / research-kick
// callsites can all read & update without prop-drilling. Reset on every
// startNewCase. The plan endpoint receives the running totals in its
// request body and logs a [session-total] summary line we can grep.
function resetSessionCost(caseId) {
  window.__sessionCost = {
    caseId,
    chat: 0,
    research: 0,
    briefing: 0,
    profile: 0,
    strategiq: 0,
    webSearchCalls: 0,
    chatTurns: 0,
    researchAgents: 0,
  };
}
function addChatCost(breakdown) {
  if (!window.__sessionCost) return;
  const s = window.__sessionCost;
  s.chat += breakdown?.chat || 0;
  s.chat += breakdown?.archetype || 0;
  s.briefing += breakdown?.briefing || 0;
  s.chatTurns += 1;
}
function addResearchCost(resp) {
  if (!window.__sessionCost) return;
  const s = window.__sessionCost;
  s.research += resp?._cost || 0;
  s.webSearchCalls += resp?._webSearchCalls || 0;
  s.researchAgents += resp?._agentCount || 0;
}
function addProfileCost(resp) {
  if (!window.__sessionCost) return;
  window.__sessionCost.profile += resp?._cost || 0;
}
function addStrategiqCost(resp) {
  if (!window.__sessionCost) return;
  window.__sessionCost.strategiq += resp?._cost || 0;
}
window.SessionCost = { reset: resetSessionCost, addChatCost, addResearchCost, addProfileCost, addStrategiqCost };

// The procurement coach is always Giuseppe under the hood — but the user
// only sees the institutional product. No coach-picker.
const PROCUREMENT_COACH = {
  id: "giuseppe",
  name: "CABL Procurement Coach",
  title: "Procurement Negotiation Intelligence",
  domain: "procurement",
  // No portrait, no warm avatar. The chat UI will use an institutional badge.
  swatch: ["#1E1E5A", "#EAEAEE"],
};

const PROCUREMENT_SITUATION = {
  id: "procurement",
  kicker: "Procurement & commercial negotiation",
  title: "Procurement & commercial negotiation",
  coachId: "giuseppe",
};

const PLAN_LOADING_STEPS = [
  "Reviewing your case…",
  "Mapping out the other side…",
  "Pressure-testing the cost story…",
  "Comparing your alternatives…",
  "Designing your three opening packages…",
  "Drafting your opening script…",
  "Building the question plan…",
  "Anticipating their tactics…",
  "Pulling it all together…",
];

function PlanLoading() {
  const [stepIdx, setStepIdx] = useStateApp(0);
  useEffectApp(() => {
    const t = setInterval(() => {
      setStepIdx((i) => (i + 1) % PLAN_LOADING_STEPS.length);
    }, 9000);
    return () => clearInterval(t);
  }, []);
  return (
    <div className="screen plan-screen">
      <div className="plan-loading">
        <div className="plan-loading-mark">
          <img src="assets/cabl-logo.png" alt="CABL"/>
        </div>
        <div className="kicker">Building your plan</div>
        <h2 className="display-sm plan-loading-step">{PLAN_LOADING_STEPS[stepIdx]}</h2>
        <p className="lede">This usually takes 30–90 seconds. For more complex cases it can take a few minutes — sit back and enjoy your coffee :-)</p>
        <div className="plan-loading-dots"><span/><span/><span/></div>
      </div>
    </div>
  );
}

function AppBootLoading() {
  return (
    <div className="screen plan-screen">
      <div className="plan-loading">
        <div className="plan-loading-mark"><img src="assets/cabl-logo.png" alt="CABL"/></div>
        <div className="kicker">Opening your workspace</div>
        <h2 className="display-sm">Checking your secure session…</h2>
        <div className="plan-loading-dots"><span/><span/><span/></div>
      </div>
    </div>
  );
}

function IngestingBriefing({ briefing, status, error, onRetry, onSkip }) {
  const fileLabel = briefing
    ? `${briefing.fileName} — ${briefing.pageCount} ${briefing.pageCount === 1 ? "page" : "pages"}`
    : "your briefing";
  const steps = [
    `Reading ${fileLabel}, in your browser…`,
    "Pulling out facts and counterpart details…",
    "Mapping to your 8 discovery checkpoints…",
    "Reviewing what's covered so far…",
    "Preparing your first session…",
  ];
  const [stepIdx, setStepIdx] = useStateApp(0);
  const [slowWarn, setSlowWarn] = useStateApp(false);
  useEffectApp(() => {
    if (status !== "loading") return undefined;
    const t = setInterval(() => setStepIdx((i) => (i + 1) % steps.length), 4500);
    const slow = setTimeout(() => setSlowWarn(true), 45000);
    return () => { clearInterval(t); clearTimeout(slow); };
  }, [status]);

  if (status === "error") {
    return (
      <div className="screen plan-screen">
        <div className="plan-loading">
          <div className="plan-loading-mark"><img src="assets/cabl-logo.png" alt="CABL"/></div>
          <div className="kicker">Couldn't read the briefing</div>
          <h2 className="display-sm">Something went wrong on the coaching backend.</h2>
          <p className="lede"><code>{error || "Unknown error"}</code></p>
          <div style={{ display: "flex", gap: 12, marginTop: 12 }}>
            <button className="btn-ghost" onClick={onSkip}>
              <IconText name="message-square">Continue by chat instead</IconText>
            </button>
            <button className="btn-primary" onClick={onRetry}>
              <IconText name="rotate-cw">Try again</IconText>
            </button>
          </div>
        </div>
      </div>
    );
  }

  return (
    <div className="screen plan-screen">
      <div className="plan-loading">
        <div className="plan-loading-mark"><img src="assets/cabl-logo.png" alt="CABL"/></div>
        <div className="kicker">Ingesting your briefing</div>
        <h2 className="display-sm plan-loading-step">{steps[stepIdx]}</h2>
        <p className="lede">
          {slowWarn
            ? "Large briefings can take up to a minute — almost there."
            : "The original PDF stays in your browser. Extracted text is routed through the app backend to your AI provider."}
        </p>
        <div className="plan-loading-dots"><span/><span/><span/></div>
      </div>
    </div>
  );
}

function PlanError({ error, onBack, onRetry }) {
  return (
    <div className="screen plan-screen">
      <div className="plan-loading">
        <div className="plan-loading-mark">
          <img src="assets/cabl-logo.png" alt="CABL"/>
        </div>
        <div className="kicker">Plan didn't generate</div>
        <h2 className="display-sm">Something went sideways building the plan.</h2>
        <p className="lede"><code>{error}</code></p>
        <div style={{ display: "flex", gap: 12, marginTop: 12 }}>
          <button className="btn-ghost" onClick={onBack}>
            <IconText name="arrow-left">Back to the conversation</IconText>
          </button>
          <button className="btn-primary" onClick={onRetry}>
            <IconText name="rotate-cw">Try again</IconText>
          </button>
        </div>
      </div>
    </div>
  );
}

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [runtimeConfig, setRuntimeConfig] = useStateApp(null);
  const [runtimeConfigReady, setRuntimeConfigReady] = useStateApp(false);
  const [onboardingPreviewDone, setOnboardingPreviewDone] = useStateApp(false);

  // Auth state — drives whether we show login / app.
  const [authReady, setAuthReady] = useStateApp(false);
  const [user, setUser] = useStateApp(null);
  const [authView, setAuthView] = useStateApp("login"); // login | signup
  const [onboardingReady, setOnboardingReady] = useStateApp(false);
  const [onboardingComplete, setOnboardingComplete] = useStateApp(false);

  // App phase (only meaningful when authenticated).
  const [phase, setPhase] = useStateApp("workspace"); // workspace | ingesting | chat | plan | settings | pricing
  const [currentCaseId, setCurrentCaseId] = useStateApp(null);
  const [discovery, setDiscovery] = useStateApp(null);
  const [plan, setPlan] = useStateApp(null);
  const [planStatus, setPlanStatus] = useStateApp("idle"); // idle | loading | ready | error
  const [planError, setPlanError] = useStateApp(null);

  // Briefing-intake state (only set when user uploaded a PDF).
  const [briefing, setBriefing] = useStateApp(null);
  const [ingestStatus, setIngestStatus] = useStateApp("idle"); // idle | loading | error
  const [ingestError, setIngestError] = useStateApp(null);
  const [chatInitial, setChatInitial] = useStateApp(null); // { messages, progress, archetypeClassification, briefingExtract }

  // BYO key — read from session/device storage; recomputed when user changes it via Settings.
  const [byoKeyTick, setByoKeyTick] = useStateApp(0);
  const [creditStatus, setCreditStatus] = useStateApp(null);
  const aiAccess = (() => {
    const base = runtimeConfig?.aiAccess || {};
    const mode = user?.aiAccessMode || base.mode || "self_serve";
    const companyManaged = mode === "company_managed";
    const userAllow = typeof user?.allowUserKeys === "boolean" ? user.allowUserKeys : null;
    return {
      ...base,
      mode,
      allowUserKeys: companyManaged ? false : (userAllow !== null ? userAllow : base.allowUserKeys !== false),
      companyName: user?.companyLicenseName || base.companyName || user?.company || null,
      companySeats: user?.companyLicenseSeats || base.companySeats || null,
    };
  })();
  const byoKeyStatus = (() => {
    if (aiAccess.mode === "company_managed" || aiAccess.allowUserKeys === false) {
      return {
        kind: "ok",
        label: "Company AI access",
        tooltip: "Your organization has already configured AI access. No personal API key is needed.",
      };
    }
    const present = window.ByoKey?.isSet();
    if (present) {
      const storage = window.ByoKey?.storageKind?.();
      const provider = window.ByoKey?.providerName?.() || "AI";
      return {
        kind: "ok",
        label: storage === "device" ? `Your ${provider} key in use` : `Session ${provider} key in use`,
        tooltip:
          storage === "device"
            ? `Requests are routed through this app backend using the ${provider} key remembered on this device.`
            : `Requests are routed through this app backend using the ${provider} key stored for this browser session.`,
      };
    }
    return {
      kind: "demo",
      label: "Platform credits in use",
      tooltip: "CABL's platform AI setup is being used. Add your own key in Settings if you want provider usage billed to your own account.",
    };
  })();
  const visibleCreditStatus = aiAccess.mode === "company_managed" ? null : creditStatus;

  useEffectApp(() => {
    document.documentElement.style.setProperty("--accent", t.accent);
    document.documentElement.style.setProperty("--display-font", `"${t.displayFont}", "Newsreader", Georgia, serif`);
    document.documentElement.dataset.density = t.density;
  }, [t.accent, t.displayFont, t.density]);

  useEffectApp(() => {
    let alive = true;
    window.Auth.getConfig?.()
      .then((cfg) => {
        if (alive) setRuntimeConfig(cfg || null);
      })
      .catch(() => {
        if (alive) setRuntimeConfig(null);
      })
      .finally(() => {
        if (alive) setRuntimeConfigReady(true);
      });
    window.Auth.getCurrentUser()
      .then((u) => {
        if (!alive) return;
        setUser(u);
        setAuthReady(true);
      })
      .catch(() => {
        if (!alive) return;
        setUser(null);
        setAuthReady(true);
      });
    return () => { alive = false; };
  }, []);

  useEffectApp(() => {
    if (!user) {
      setOnboardingReady(false);
      setOnboardingComplete(false);
      return;
    }
    // Enterprise (company-managed) users skip onboarding entirely — their org has
    // already configured AI access, so there's nothing for them to choose.
    const companyManaged =
      user?.aiAccessMode === "company_managed" ||
      runtimeConfig?.aiAccess?.mode === "company_managed";
    setOnboardingComplete(companyManaged || window.Onboarding?.hasCompleted?.(user) || false);
    setOnboardingReady(true);
  }, [user?.id, runtimeConfig]);

  useEffectApp(() => {
    if (!user) {
      setCreditStatus(null);
      return undefined;
    }
    let alive = true;
    (async () => {
      try {
        const resp = await fetch("/api/credits", {
          credentials: "same-origin",
          headers: await window.Auth.apiHeaders(),
        });
        const data = await resp.json().catch(() => ({}));
        if (alive && data.credits) setCreditStatus(data.credits);
      } catch {
        if (alive) setCreditStatus(null);
      }
    })();
    return () => { alive = false; };
  }, [user?.id]);

  // Global "open pricing" signal — dispatched by the topbar credit pill and the
  // credit-wall CTA so any screen can route to the upgrade page without
  // prop-drilling through every child component.
  useEffectApp(() => {
    const open = () => setPhase("pricing");
    window.addEventListener("cabl:open-pricing", open);
    return () => window.removeEventListener("cabl:open-pricing", open);
  }, []);

  // -------------------------------------------------------------------------
  // Auth handlers
  // -------------------------------------------------------------------------
  function onAuthed(u) {
    setUser(u);
    setOnboardingReady(false);
    setOnboardingComplete(false);
    setPhase("workspace");
  }

  async function signOut() {
    await window.Auth.logOut().catch(() => {});
    setUser(null);
    setCreditStatus(null);
    setAuthView("login");
    setOnboardingReady(false);
    setOnboardingComplete(false);
    setPhase("workspace");
    setCurrentCaseId(null);
    setPlan(null);
    setPlanStatus("idle");
  }

  // -------------------------------------------------------------------------
  // Case lifecycle
  // -------------------------------------------------------------------------
  function startNewCase(payload) {
    const briefingPayload = payload && payload.briefing ? payload.briefing : null;
    const newId = window.Workspace.newCaseId();
    setCurrentCaseId(newId);
    window.SessionCost.reset(newId);
    setPlan(null);
    setPlanStatus("idle");
    setPlanError(null);
    setChatInitial(null);
    setIngestError(null);
    if (briefingPayload) {
      setBriefing(briefingPayload);
      setIngestStatus("loading");
      setPhase("ingesting");
      void runBriefingIntake(briefingPayload, newId);
    } else {
      setBriefing(null);
      setIngestStatus("idle");
      setPhase("chat");
    }
  }

  async function runBriefingIntake(b, caseIdForCall = null) {
    const briefingUserText = `[Briefing document attached: ${b.fileName} · ${b.pageCount} pages]\n\n${b.text}`;
    const briefingUserMessage = {
      who: "user",
      text: briefingUserText,
      attachment: { kind: "pdf", fileName: b.fileName, pageCount: b.pageCount, sizeBytes: b.sizeBytes },
    };
    try {
      const resp = await fetch("/api/chat", {
        method: "POST",
        headers: await window.Auth.apiHeaders(),
        body: JSON.stringify({
          coachId: PROCUREMENT_COACH.id,
          situation: PROCUREMENT_SITUATION.id,
          caseId: caseIdForCall || currentCaseId,
          messages: [briefingUserMessage],
          progress: {},
          ...(window.ByoKey?.requestFields?.() || {}),
        }),
      });
      const data = await resp.json();
      if (data.credits) setCreditStatus(data.credits);
      if (data.error) throw new Error(data.error);
      window.SessionCost.addChatCost(data._costBreakdown);
      const coachMsg = { who: "coach", text: data.reply, final: !!data.ready_for_plan };
      setChatInitial({
        messages: [briefingUserMessage, coachMsg],
        progress: data.progress || {},
        ready_for_plan: !!data.ready_for_plan,
        archetypeClassification: data.archetypeClassification || null,
        briefingExtract: data.briefingExtract || null,
      });
      setIngestStatus("idle");
      setPhase("chat");
    } catch (err) {
      console.error("briefing intake failed:", err);
      setIngestError(err.message || String(err));
      setIngestStatus("error");
    }
  }

  function retryBriefingIntake() {
    if (!briefing) return;
    setIngestError(null);
    setIngestStatus("loading");
    void runBriefingIntake(briefing);
  }

  function skipBriefingToChat() {
    setBriefing(null);
    setChatInitial(null);
    setIngestStatus("idle");
    setIngestError(null);
    setPhase("chat");
  }

  function openCase(c) {
    setCurrentCaseId(c.id);
    setBriefing(null);
    // Restore the saved discovery context so "Back to conversation" keeps the
    // conversation, and regenerating the plan reuses the (expensive) counterpart
    // profile + strategic-sourcing brief instead of re-running them.
    setChatInitial(
      c.messages?.length
        ? {
            messages: c.messages,
            progress: c.progress || {},
            ready_for_plan: !!c.plan,
            archetypeClassification:
              c.archetypeClassification || (c.archetypeLabel ? { archetypeLabel: c.archetypeLabel } : null),
            kahnemanHandoff: c.kahnemanHandoff || null,
            strategiqBrief: c.strategiqBrief || null,
          }
        : null
    );
    if (c.plan) {
      setPlan(c.plan);
      setPlanStatus("ready");
      setPhase("plan");
    } else {
      setPhase("chat");
    }
  }

  function backToWorkspace() {
    setPhase("workspace");
  }

  // -------------------------------------------------------------------------
  // Plan generation
  // -------------------------------------------------------------------------
  async function buildPlan(data) {
    setDiscovery(data);
    setPhase("plan");

    if (APP_IS_DEMO) {
      setPlan(null);
      setPlanStatus("ready");
      return;
    }

    setPlanStatus("loading");
    setPlanError(null);
    try {
      const resp = await fetch("/api/plan", {
        method: "POST",
        headers: await window.Auth.apiHeaders(),
        body: JSON.stringify({
          coachId: data.coach.id,
          situation: data.situation.id,
          caseId: currentCaseId,
          messages: data.messages,
          progress: data.progress,
          research: data.research || null,
          domain: data.domain || null,
          ...(window.ByoKey?.requestFields?.() || {}),
          archetypeClassification: data.archetypeClassification || null,
          kahnemanHandoff: data.kahnemanHandoff || null,
          strategiqBrief: data.strategiqBrief || null,
          sessionCostBreakdown: window.__sessionCost || null,
          userEmail: user?.email || null,
        }),
      });
      const body = await resp.json();
      if (body.credits) setCreditStatus(body.credits);
      if (body.error) throw new Error(body.error);
      setPlan(body);
      setPlanStatus("ready");

      // Persist case
      try {
        await window.Workspace.saveCase({
          id: currentCaseId,
          title: extractCaseTitle(data.messages, body),
          archetypeLabel: body.archetypeClassification?.archetypeLabel || data.archetypeClassification?.archetypeLabel || "Procurement",
          phase: "plan",
          date: new Date().toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric" }),
          plan: body,
          messages: data.messages,
          progress: data.progress,
          archetypeClassification: data.archetypeClassification || null,
          kahnemanHandoff: data.kahnemanHandoff || null,
          strategiqBrief: data.strategiqBrief || null,
        });
      } catch (storageErr) {
        console.warn("case persistence failed:", storageErr);
      }
    } catch (err) {
      console.error(err);
      setPlanError(err.message);
      setPlanStatus("error");
    }
  }

  function extractCaseTitle(messages, plan) {
    if (plan?.title) return plan.title;
    const firstUser = (messages || []).find(m => m.who === "user");
    if (firstUser?.text) return firstUser.text.slice(0, 70).replace(/\s+\S*$/, "") + (firstUser.text.length > 70 ? "…" : "");
    return "Procurement negotiation";
  }

  function retryPlan() {
    if (discovery) buildPlan(discovery);
  }

  // -------------------------------------------------------------------------
  // Render
  // -------------------------------------------------------------------------
  if (ONBOARDING_PREVIEW_ENABLED) {
    if (!runtimeConfigReady) {
      return (
        <div className="app-root">
          <AppBootLoading/>
        </div>
      );
    }

    const previewCompany = String(ONBOARDING_PREVIEW).toLowerCase() === "company";
    const previewUser = previewCompany
      ? {
          id: "preview-company",
          email: "buyer@acme.example",
          fullName: "Procurement Buyer",
          company: "Acme Procurement",
          aiAccessMode: "company_managed",
          companyLicenseName: "Acme Procurement",
          companyLicenseSeats: 10,
        }
      : {
          id: "preview-self",
          email: "buyer@example.com",
          fullName: "Procurement Buyer",
          company: "CABL Preview",
        };
    const previewAiAccess = previewCompany
      ? { mode: "company_managed", allowUserKeys: false, companyName: "Acme Procurement", companySeats: 10 }
      : { ...(runtimeConfig?.aiAccess || {}), mode: "self_serve", allowUserKeys: true };

    if (onboardingPreviewDone) {
      return (
        <div className="app-root">
          <div className="screen onboarding-screen">
            <main className="onboarding-shell">
              <div className="onboarding-brand">
                <img src="assets/cabl-logo.png" alt="CABL"/>
                <span>CABL Procurement Lab</span>
              </div>
              <section className="onboarding-panel">
                <div className="onboarding-kicker">Preview complete</div>
                <h1 className="display-sm">That's the end of the onboarding step.</h1>
                <p className="onboarding-lede">In the real app, the user now lands in the procurement workspace.</p>
                <div className="onboarding-actions">
                  <button className="btn-primary big" onClick={() => setOnboardingPreviewDone(false)}>
                    <IconText name="rotate-cw">Show onboarding again</IconText>
                  </button>
                </div>
              </section>
            </main>
          </div>
        </div>
      );
    }

    return (
      <div className="app-root">
        <OnboardingScreen
          user={previewUser}
          aiAccess={previewAiAccess}
          creditStatus={{ remaining: 200, allowance: 200 }}
          onComplete={() => setOnboardingPreviewDone(true)}
        />
      </div>
    );
  }

  if (!authReady) {
    return (
      <div className="app-root">
        <AppBootLoading/>
      </div>
    );
  }

  if (!user) {
    return (
      <div className="app-root">
        {authView === "login" ? (
          <LogInScreen onAuthed={onAuthed} onSwitch={setAuthView}/>
        ) : (
          <SignUpScreen onAuthed={onAuthed} onSwitch={setAuthView}/>
        )}
      </div>
    );
  }

  if (!runtimeConfigReady || !onboardingReady) {
    return (
      <div className="app-root">
        <AppBootLoading/>
      </div>
    );
  }

  if (!onboardingComplete) {
    return (
      <div className="app-root">
        <OnboardingScreen
          user={user}
          aiAccess={aiAccess}
          creditStatus={creditStatus}
          onComplete={() => {
            setOnboardingComplete(true);
            setByoKeyTick(v => v + 1);
          }}
        />
      </div>
    );
  }

  return (
    <div className="app-root">
      {t.showWatermark && <div className="watermark no-print">DRAFT — not for distribution</div>}

      {phase === "workspace" && (
        <WorkspaceScreen
          user={user}
          onNewCase={startNewCase}
          onOpenCase={openCase}
          onOpenSettings={() => setPhase("settings")}
          onSignOut={signOut}
          byoKeyStatus={byoKeyStatus}
          creditStatus={visibleCreditStatus}
        />
      )}

      {phase === "settings" && (
        <SettingsScreen
          user={user}
          onClose={backToWorkspace}
          onSignOut={signOut}
          byoKeyStatus={byoKeyStatus}
          creditStatus={visibleCreditStatus}
          aiAccess={aiAccess}
          onByoKeyChange={() => setByoKeyTick(v => v + 1)}
        />
      )}

      {phase === "pricing" && (
        <PricingScreen
          user={user}
          billing={runtimeConfig?.billing}
          creditStatus={creditStatus}
          byoKeyStatus={byoKeyStatus}
          onBack={backToWorkspace}
          onOpenSettings={() => setPhase("settings")}
          onSignOut={signOut}
        />
      )}

      {phase === "ingesting" && (
        <IngestingBriefing
          briefing={briefing}
          status={ingestStatus}
          error={ingestError}
          onRetry={retryBriefingIntake}
          onSkip={skipBriefingToChat}
        />
      )}

      {phase === "chat" && (
        <ChatScreen
          situation={PROCUREMENT_SITUATION}
          coach={PROCUREMENT_COACH}
          user={user}
          caseId={currentCaseId}
          byoKeyStatus={byoKeyStatus}
          creditStatus={visibleCreditStatus}
          onCreditsUpdate={setCreditStatus}
          chatInitial={chatInitial}
          onComplete={buildPlan}
          onBack={backToWorkspace}
          onOpenSettings={() => setPhase("settings")}
          onSignOut={signOut}
        />
      )}

      {phase === "plan" && planStatus === "loading"  && <PlanLoading/>}
      {phase === "plan" && planStatus === "error"    && <PlanError error={planError} onBack={() => setPhase("chat")} onRetry={retryPlan}/>}
      {phase === "plan" && planStatus === "ready"    && (
        <ActionPlan
          situation={PROCUREMENT_SITUATION}
          coach={PROCUREMENT_COACH}
          plan={plan}
          user={user}
          byoKeyStatus={byoKeyStatus}
          creditStatus={visibleCreditStatus}
          onBack={() => setPhase("chat")}
          onRestart={backToWorkspace}
          onOpenSettings={() => setPhase("settings")}
          onSignOut={signOut}
        />
      )}

      <TweaksPanel title="Tweaks">
        <TweakSection label="Look & feel">
          <TweakColor
            label="Accent color"
            value={t.accent}
            onChange={(v) => setTweak("accent", v)}
            options={["#E63946", "#1E1E5A", "#6A9A7A", "#6A8FB5", "#9A7EB5"]}
          />
          <TweakSelect
            label="Display font"
            value={t.displayFont}
            onChange={(v) => setTweak("displayFont", v)}
            options={["Newsreader", "Fraunces", "Plus Jakarta Sans", "Nunito"]}
          />
          <TweakRadio
            label="Density"
            value={t.density}
            onChange={(v) => setTweak("density", v)}
            options={["compact", "comfortable"]}
          />
        </TweakSection>
        <TweakSection label="Debug">
          <TweakToggle
            label="Show DRAFT watermark"
            value={t.showWatermark}
            onChange={(v) => setTweak("showWatermark", v)}
          />
        </TweakSection>
      </TweaksPanel>
    </div>
  );
}

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