/* MatchPlan.ai — Prepare new + Prep report (MatchIQ style). */

const DEPARTMENTS = ["Engineering", "Sales", "Marketing", "Operations", "Finance", "HR", "IT", "Executive"];

// ============ PREP REPORT ============
function PrepViewPage({ id, path }) {
  const toast = useToast();
  const prep = MP.getPrep(id);
  const [, force] = React.useReducer(x => x + 1, 0);
  const [pdfBusy, setPdfBusy] = React.useState(false); // before the early return (rules of hooks)
  if (!prep) {
    return (
      <Shell path={path} width="mp-w-3xl">
        <Card pad><div style={{ textAlign: "center", padding: 24 }}>
          <p style={{ color: "var(--fg-2)" }}>Hmm, we couldn't find that prep.</p>
          <Button variant="secondary" style={{ marginTop: 12 }} onClick={() => navigate("/dashboard")}>Back to home</Button>
        </div></Card>
      </Shell>
    );
  }
  const d = prep.data;
  const hasPostCall = !!MP.getPostCall(id);

  const copyAll = () => { try { navigator.clipboard.writeText(buildBriefMarkdown(prep)); } catch (e) {} toast.success("Copied — paste into ChatGPT, Claude, or any LLM to keep refining."); };
  const markDone = async () => {
    const saved = MP.markDone(id);
    force();
    try {
      await saved;
      toast.success("Marked as done. Nice call!");
    } catch (e) {
      // #87: the success toast used to fire unconditionally.
      toast.error("Couldn't mark that as done. Try again.");
    }
  };

  // Real PDF download: the server renders the brief on demand (GET
  // /api/briefs/:id/pdf, authenticated by the shared session cookie) and we save the returned blob.
  // Demo mode (file:// / signed out) has no server brief to render — say so.
  const downloadPdf = async () => {
    if (pdfBusy) return;
    if (!MP.apiOn || !window.PSA || !MP.isReturning()) { toast.error("Sign in to download your brief as a PDF."); return; }
    setPdfBusy(true);
    try {
      const headers = {};
      try { const acct = localStorage.getItem("presalesagent.activeAccountId"); if (acct) headers["X-Account-Id"] = acct; } catch (e) {}
      const res = await fetch("/api/briefs/" + encodeURIComponent(id) + "/pdf", { headers, credentials: "same-origin" });
      if (!res.ok) {
        // pitchiq#471: this is the one guarded request with a `fetch` of its own (it needs a blob), so
        // it hands a failed answer to the path `req()` uses. api.js decides: for a member removed from
        // their workspace the app flips to the refusal page, and the toast in the catch below is then
        // not raised (ui.jsx `useToast` is quiet while a refusal shows); for anything else it does
        // nothing and that toast shows as before.
        let refused = null;
        try { refused = await res.json(); } catch (e) {}
        PSA.noteSessionRefusal(res.status, refused);
        throw new Error("http " + res.status);
      }
      const blob = await res.blob();
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      const slug = (prep.prospect || "brief").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60) || "brief";
      a.href = url; a.download = "game-day-brief-" + slug + ".pdf";
      document.body.appendChild(a); a.click(); a.remove();
      setTimeout(() => { try { URL.revokeObjectURL(url); } catch (e) {} }, 4000);
      toast.success("Brief downloaded as PDF.");
    } catch (e) {
      toast.error("Couldn't generate the PDF. Please try again.");
    } finally { setPdfBusy(false); }
  };

  return (
    <Shell path={path} width="mp-w-3xl">
      <PageHeader title={prep.prospect}
        eyebrow={<><Icon name="FileText" size={13} /> Game Day Brief</>}
        subtitle={(() => { const cs = prep.contacts && prep.contacts.filter(c => c.name); const who = cs && cs.length ? (cs.length === 1 ? cs[0].name : cs.length + " stakeholders") + " · " : ""; return who + prep.stage + " call · prepped " + relTime(prep.createdAt).toLowerCase(); })()}
        back={{ to: "/dashboard", label: "Back to home" }}
        actions={<>
          <Button variant="secondary" size="sm" icon="Download" disabled={pdfBusy} onClick={downloadPdf}>{pdfBusy ? "Preparing…" : "PDF"}</Button>
          <Button variant="secondary" size="sm" icon="Share2"
            onClick={() => { try { navigator.clipboard.writeText(window.location.href); } catch (e) {} toast.success("Link copied to clipboard."); }}>Share</Button>
        </>} />

      {prep.done && (
        <button onClick={() => navigate("/post-call/" + id)} className="mp-fade"
          style={{ width: "100%", display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12, marginBottom: 20, padding: "14px 18px", borderRadius: "var(--radius-lg)", border: 0, background: "var(--accent-soft)", color: "var(--accent)", cursor: "pointer", fontFamily: "var(--font-primary)", fontWeight: 700, fontSize: "var(--fs-subtitle-2)" }}>
          <span style={{ display: "flex", alignItems: "center", gap: 10 }}><Icon name="FileAudio" size={18} /> {hasPostCall ? "View your post-call analysis" : "Add post-call notes & get a verdict"}</span>
          <Icon name="ArrowRight" size={18} />
        </button>
      )}

      <div className="mp-stack">
        {/* 30-second game plan — the one-glance summary for an impatient rep */}
        {d.gameplan && (
          <div className="mp-gameplan mp-fade">
            <div className="mp-gameplan__head">
              <span className="mp-gameplan__badge"><Icon name="Zap" size={15} strokeWidth={2.4} /> 30-second game plan</span>
              {d.fit && <Chip tone="green" icon="Target">{d.gameplan.verdict}</Chip>}
            </div>
            <div className="mp-gameplan__grid">
              <div className="mp-gp-item">
                <span className="mp-gp-item__k"><Icon name="MessageSquare" size={15} /> Open with</span>
                <p>{d.gameplan.say}</p>
              </div>
              <div className="mp-gp-item">
                <span className="mp-gp-item__k"><Icon name="Award" size={15} /> Prove it</span>
                <p>{d.gameplan.prove}</p>
              </div>
              <div className="mp-gp-item">
                <span className="mp-gp-item__k"><Icon name="HelpCircle" size={15} /> First question</span>
                <p>“{d.gameplan.ask}”</p>
              </div>
              <div className="mp-gp-item mp-gp-item--watch">
                <span className="mp-gp-item__k"><Icon name="Eye" size={15} /> Watch for</span>
                <p>{d.gameplan.watch}</p>
              </div>
            </div>
          </div>
        )}

        {/* snapshot */}
        <Card accent="blue" className="mp-fade">
          <div className="mp-card__pad">
            <div className="mp-snapshot__top">
              <div className="mp-cellflex" style={{ gap: 14 }}>
                <Avatar name={prep.prospect} color="blue" size={46} soft />
                <div>
                  <a href={"https://" + prep.url.replace(/^https?:\/\//, "")} target="_blank" rel="noreferrer"
                    style={{ display: "inline-flex", alignItems: "center", gap: 7, fontWeight: 900, fontSize: "var(--fs-heading-3)", color: "var(--fg-1)", textDecoration: "none" }}>
                    {prep.prospect} <Icon name="ExternalLink" size={15} style={{ color: "var(--fg-3)" }} />
                  </a>
                  <div style={{ fontSize: "var(--fs-body-3)", color: "var(--fg-2)" }}>{prep.url}</div>
                </div>
              </div>
              <Chip tone={confTone[d.confidence]} icon={confIcon[d.confidence]}>{confLabel[d.confidence]}</Chip>
            </div>
            <p className="mp-snapshot__story">{d.story}</p>
            <div className="mp-statgrid">
              <Substat icon="Building2" label="Industry" value={d.industry} />
              <Substat icon="Users" label="Employees" value={"~" + d.employees.toLocaleString()} num />
              <Substat icon="Radar" label="Signals" value={d.findings.length + " found"} num />
            </div>
          </div>
        </Card>

        {/* seller-to-buyer ICP fit — the core differentiator */}
        {d.fit && (
          <Card accent="green" className="mp-fade">
            <div className="mp-card__pad">
              <div className="mp-eyebrow is-green" style={{ marginBottom: 10 }}><Icon name="Target" size={14} /> Seller-to-buyer fit</div>
              <div style={{ display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap" }}>
                <h3 className="text-heading-3" style={{ margin: 0 }}>You sell {d.fit.product}.</h3>
                <Chip tone="green" icon="Check">{d.fit.verdict}</Chip>
              </div>
              <ul style={{ listStyle: "none", margin: "14px 0 0", padding: 0, display: "flex", flexDirection: "column", gap: 11 }}>
                {d.fit.points.map((pt, i) => (
                  <li key={i} style={{ display: "flex", gap: 10, alignItems: "flex-start", fontSize: "var(--fs-body-1)", color: "var(--fg-1)", lineHeight: 1.5 }}>
                    <span style={{ color: "var(--green-1)", flexShrink: 0, marginTop: 2 }}><Icon name="Check" size={17} strokeWidth={2.4} /></span>{pt}
                  </li>
                ))}
              </ul>
            </div>
          </Card>
        )}

        {/* who you're meeting — prospect stakeholders */}
        {d.stakeholders && d.stakeholders.length > 0 && (
          <Section icon="Users" title="Who you're meeting" subtitle={d.stakeholders.length === 1 ? "Your read on the person across the table." : "Your read on each person in the room — and how to win them."}>
            <div className="mp-teamgrid">
              {d.stakeholders.map((p, i) => (
                <div key={i} className="mp-teamcard">
                  <Avatar name={p.name} color={["blue", "purple", "green", "gold"][i % 4]} size={40} />
                  <div style={{ minWidth: 0 }}>
                    <div className="mp-teamcard__name">{p.name}</div>
                    <div className="mp-teamcard__role">{p.title || p.kind}</div>
                    <div className="mp-stake__role">{p.kind}</div>
                    <div className="mp-teamcard__reason">{p.angle}</div>
                    {p.contact && <div className="mp-stake__contact"><Icon name={/@/.test(p.contact) ? "Mail" : "Linkedin"} size={12} /> {p.contact}</div>}
                  </div>
                </div>
              ))}
            </div>
          </Section>
        )}

        {/* deep-research findings */}
        <Section icon="Globe" title="What we found" subtitle="Signals pulled from across the web — your edge going in.">
          <div className="mp-findings">
            {d.findings.map((fnd, i) => (
              <div key={i} className="mp-finding">
                <span className="mp-finding__icon"><Icon name="Sparkle" size={15} /></span>
                <div>
                  <div className="mp-finding__text">{fnd.text}</div>
                  <div className="mp-finding__src"><Icon name="Link2" size={12} style={{ verticalAlign: "-2px", marginRight: 4 }} />{fnd.src}</div>
                </div>
              </div>
            ))}
          </div>
        </Section>

        {/* agenda */}
        <Section icon="Clock" title="Your 30-minute agenda" subtitle="A clean arc from warm open to next steps.">
          <ol className="mp-agenda">
            {d.agenda.map((a, i) => (
              <li key={i}>
                <span className="mp-agenda__time">{a.time}</span>
                <div><div className="mp-agenda__label">{a.label}</div><div className="mp-agenda__detail">{a.detail}</div></div>
              </li>
            ))}
          </ol>
        </Section>

        {/* smart questions to ask */}
        {d.questions && d.questions.length > 0 && (
          <Section icon="HelpCircle" title="Smart questions to ask" subtitle="Read these straight off the brief — they open up the real conversation.">
            <ol className="mp-questions">
              {d.questions.map((q, i) => (
                <li key={i}><span className="mp-questions__num">{i + 1}</span><span className="mp-questions__text">{q}</span></li>
              ))}
            </ol>
          </Section>
        )}

        {/* pitch points */}
        <Section icon="MessagesSquare" title="Pitch points" subtitle="Three angles to lead with.">
          <div className="mp-pitch">
            {d.pitch.map((p, i) => (
              <div key={i} className="mp-pitch__item">
                <span className="mp-pitch__num">{i + 1}</span>
                <div>
                  <h4 className="mp-pitch__h">{p.headline}</h4>
                  <p className="mp-pitch__body">{p.body}</p>
                  <div className="mp-pitch__why"><Icon name="Lightbulb" size={15} /> <span><b>Why it lands:</b> {p.why}</span></div>
                </div>
              </div>
            ))}
          </div>
        </Section>

        {/* objections */}
        <Section icon="ShieldAlert" title="Likely objections" subtitle="What they'll push on — and how to answer.">
          <div className="mp-obj">
            {d.objections.map((o, i) => <Objection key={i} q={o.q} a={o.a} defaultOpen={i === 0} />)}
          </div>
        </Section>

        {/* roles to bring */}
        <Section icon="Users" title="Roles to consider bringing" subtitle="The kind of teammate who strengthens the room — pull in whoever fills these on your team.">
          <TeamRecommender team={d.team} soloFit={d.soloFit} />
        </Section>

        {/* action bar */}
        <div className="mp-actionbar">
          <div className="mp-card">
            <Button variant="secondary" size="sm" icon="Copy" onClick={copyAll}>Copy as Markdown</Button>
            <Button variant="secondary" size="sm" icon="Download" disabled={pdfBusy} onClick={downloadPdf}>{pdfBusy ? "Preparing…" : "Download PDF"}</Button>
            <div style={{ flex: 1 }}></div>
            {prep.done ? <Chip tone="green" icon="Check">Marked as done</Chip>
              : <Button size="sm" icon="CircleCheck" onClick={markDone}>Mark as done</Button>}
          </div>
        </div>

        {/* feedback — thumbs up/down + report an issue */}
        <BriefFeedback briefId={id} />
      </div>
    </Shell>
  );
}

const DOWN_TAGS = ["Accuracy", "Context use", "Relevance", "Length", "Freshness", "Tone"];

/** Thumbs up/down on a brief + a lightweight issue report. Persists to the API. */
function BriefFeedback({ briefId }) {
  const toast = useToast();
  const [sentiment, setSentiment] = React.useState(null);
  const [showTags, setShowTags] = React.useState(false);
  const [tags, setTags] = React.useState([]);
  const [note, setNote] = React.useState("");
  const [reporting, setReporting] = React.useState(false);
  const [issue, setIssue] = React.useState("");
  const [busy, setBusy] = React.useState(false);
  const api = typeof PSA !== "undefined" && PSA.enabled;

  React.useEffect(() => {
    if (!api) return;
    PSA.feedback.forBrief(briefId).then(r => {
      if (r && r.rating) { setSentiment(r.rating.sentiment); setTags(r.rating.tags || []); setNote(r.rating.text || ""); }
    }).catch(() => {});
  }, [briefId]);

  const rate = async (s) => {
    setSentiment(s);
    setShowTags(s === "down");
    if (!api) { toast.success(s === "up" ? "Glad it helped!" : "Thanks — we'll use that."); return; }
    try {
      await PSA.feedback.submit({ briefId, kind: "rating", sentiment: s, surface: "Brief output", tags: s === "down" ? tags : [], text: s === "down" ? note : "" });
      toast.success(s === "up" ? "Glad it helped!" : "Thanks — your note helps us tune the briefs.");
    } catch (e) { toast.error("Couldn't save that — try again."); }
  };
  const toggleTag = (t) => setTags(ts => ts.includes(t) ? ts.filter(x => x !== t) : ts.concat(t));
  const saveDownDetail = async () => {
    if (!api) { setShowTags(false); toast.success("Thanks for the detail."); return; }
    setBusy(true);
    try {
      await PSA.feedback.submit({ briefId, kind: "rating", sentiment: "down", surface: "Brief output", tags, text: note });
      setShowTags(false); toast.success("Thanks — that goes straight to the team.");
    } catch (e) { toast.error("Couldn't save that."); } finally { setBusy(false); }
  };
  const submitIssue = async () => {
    if (!issue.trim()) return;
    setBusy(true);
    try {
      if (api) await PSA.feedback.submit({ briefId, kind: "issue", surface: "Brief output", text: issue.trim() });
      setReporting(false); setIssue(""); toast.success("Issue reported. Thank you!");
    } catch (e) { toast.error("Couldn't send that report."); } finally { setBusy(false); }
  };

  return (
    <Card className="mp-fade">
      <div className="mp-card__pad">
        <div style={{ display: "flex", alignItems: "center", gap: 14, flexWrap: "wrap" }}>
          <span style={{ fontWeight: 700, color: "var(--fg-1)" }}>Was this brief helpful?</span>
          <div style={{ display: "flex", gap: 8 }}>
            <Button variant={sentiment === "up" ? "primary" : "secondary"} size="sm" icon="ThumbsUp" onClick={() => rate("up")}>Helpful</Button>
            <Button variant={sentiment === "down" ? "primary" : "secondary"} size="sm" icon="ThumbsDown" onClick={() => rate("down")}>Needs work</Button>
          </div>
          <div style={{ flex: 1 }}></div>
          <Button variant="ghost" size="sm" icon="Flag" onClick={() => setReporting(r => !r)}>Report an issue</Button>
        </div>

        {showTags && (
          <div className="mp-fade" style={{ marginTop: 14, borderTop: "1px solid var(--border)", paddingTop: 14 }}>
            <div style={{ fontSize: "var(--fs-body-3)", color: "var(--fg-2)", marginBottom: 8 }}>What was off? (optional)</div>
            <div style={{ display: "flex", flexWrap: "wrap", gap: 8, marginBottom: 10 }}>
              {DOWN_TAGS.map(t => (
                <button key={t} onClick={() => toggleTag(t)} type="button"
                  style={{ cursor: "pointer", borderRadius: "var(--radius-full)", padding: "5px 12px", fontSize: "var(--fs-body-3)", fontWeight: 700,
                    border: "1.5px solid " + (tags.includes(t) ? "var(--accent)" : "var(--border)"),
                    background: tags.includes(t) ? "var(--accent-soft)" : "transparent",
                    color: tags.includes(t) ? "var(--accent)" : "var(--fg-2)" }}>{t}</button>
              ))}
            </div>
            <textarea className="mp-input" rows={2} placeholder="Anything specific we should fix?" value={note}
              onChange={e => setNote(e.target.value)} style={{ width: "100%", resize: "vertical" }} />
            <div style={{ marginTop: 10 }}><Button size="sm" icon="Send" disabled={busy} onClick={saveDownDetail}>Send detail</Button></div>
          </div>
        )}

        {reporting && (
          <div className="mp-fade" style={{ marginTop: 14, borderTop: "1px solid var(--border)", paddingTop: 14 }}>
            <div style={{ fontSize: "var(--fs-body-3)", color: "var(--fg-2)", marginBottom: 8 }}>Report a problem with this brief</div>
            <textarea className="mp-input" rows={3} placeholder="Describe what went wrong (wrong info, missing section, a bug…)" value={issue}
              onChange={e => setIssue(e.target.value)} style={{ width: "100%", resize: "vertical" }} />
            <div style={{ marginTop: 10, display: "flex", gap: 8 }}>
              <Button size="sm" icon="Send" disabled={busy || !issue.trim()} onClick={submitIssue}>Send report</Button>
              <Button variant="secondary" size="sm" onClick={() => setReporting(false)}>Cancel</Button>
            </div>
          </div>
        )}
      </div>
    </Card>
  );
}

function Substat({ icon, label, value, num }) {
  return (
    <div>
      <div className="mp-substat__k"><Icon name={icon} size={13} /> {label}</div>
      <div className="mp-substat__v" style={num ? { fontFamily: "var(--font-numbers)" } : null}>{value}</div>
    </div>
  );
}

function Objection({ q, a, defaultOpen }) {
  const [open, setOpen] = React.useState(!!defaultOpen);
  return (
    <div className="mp-obj__item">
      <button className="mp-obj__q" onClick={() => setOpen(o => !o)}>
        <span className="mp-obj__qtext"><Icon name="MessageCircle" size={17} /> {q}</span>
        <Icon name="ChevronDown" size={17} className={`mp-obj__chev${open ? " is-open" : ""}`} />
      </button>
      {open && <div className="mp-obj__a"><div>{a}</div></div>}
    </div>
  );
}

function TeamRecommender({ team, soloFit }) {
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
      {team.length > 0 && (
        <div className="mp-teamgrid">
          {team.map(c => (
            <div key={c.id} className="mp-teamcard">
              <span className={`mp-rolemark mp-rolemark--${c.color}`}><Icon name={c.icon || "Users"} size={20} /></span>
              <div style={{ minWidth: 0 }}>
                <div className="mp-teamcard__name">{c.role}</div>
                <div className="mp-teamcard__reason">{c.reason}</div>
              </div>
            </div>
          ))}
        </div>
      )}
      <div className={`mp-fit ${soloFit.kind === "good" ? "is-good" : "is-escalate"}`}>
        <Icon name={soloFit.kind === "good" ? "CircleCheck" : "TriangleAlert"} size={19} />
        <div>
          <div className="mp-fit__title">Are you the right person to run this?</div>
          <div className="mp-fit__text">{soloFit.text}</div>
        </div>
      </div>
    </div>
  );
}

/**
 * Build the "Copy as Markdown" clipboard payload: the brief PLUS the seller's
 * ICP/positioning profile, structured so any LLM (pasted into ChatGPT, Claude,
 * etc.) can pick it up and keep working with it. Two conventions drive the shape:
 *  - Markdown for the actual content (renders cleanly, and LLMs parse Markdown
 *    structure natively either way).
 *  - XML-style tags around each distinct block (<seller_profile>,
 *    <game_day_brief>) so the model can unambiguously tell "reference context
 *    about the seller" apart from "the brief to work on" — the same technique
 *    services/synthesis-prompt.ts uses server-side (<seller_baseline>, etc.).
 * The seller_profile section reuses MP.buildSystemPrompt() verbatim (sliced to
 * drop the "# ROLE"/"# INSTRUCTIONS" framing meant for the brief-writing AI, so
 * a pasted-in LLM doesn't mistake it for a persona to assume) — that keeps this
 * export byte-identical to whatever actually drove the brief, with no separate
 * copy of the ICP-to-prose mapping to maintain.
 * Deliberately carries NO task instructions ("help me sharpen this...") — that
 * framing primes the LLM to treat the brief as a rough draft to critique, which
 * can make an already-personalized brief read back as generic. This is just the
 * labeled data; the rep supplies their own question when they paste it in.
 */
function buildBriefMarkdown(prep) {
  const d = prep.data || {};
  const oneLine = (v) => String(v == null ? "" : v).replace(/\s+/g, " ").trim();
  const dash = (v) => oneLine(v) || "—";
  const fmtDate = (iso) => {
    const dt = new Date(iso);
    return Number.isNaN(dt.getTime()) ? "" : dt.toLocaleDateString(undefined, { month: "long", day: "numeric", year: "numeric" });
  };

  // Grounded research returns opaque redirect URLs (vertexaisearch…, 100+
  // chars) — printing those is noise. Show the human label (title, else the
  // URL's host), dedupe by label, cap the list. Mirrors services/brief-pdf.ts.
  const buildSources = (sources) => {
    const isRedirect = (u) => /vertexaisearch|grounding-api-redirect/i.test(u) || u.length > 90;
    const hostOf = (u) => { try { return new URL(u).hostname.replace(/^www\./, ""); } catch (e) { return ""; } };
    const seen = new Set();
    const items = (Array.isArray(sources) ? sources : [])
      .map((s) => {
        const uri = oneLine(s && s.uri);
        const label = oneLine(s && s.title) || (uri && !isRedirect(uri) ? hostOf(uri) : "");
        return { label, uri: uri && !isRedirect(uri) ? uri : "" };
      })
      .filter((s) => {
        if (!s.label) return false;
        const key = s.label.toLowerCase();
        if (seen.has(key)) return false;
        seen.add(key);
        return true;
      });
    const SHOW = 12;
    return {
      shown: items.slice(0, SHOW).map((s) => (s.uri && s.uri.toLowerCase() !== s.label.toLowerCase() ? `${s.label} — ${s.uri}` : s.label)),
      more: Math.max(0, items.length - SHOW),
    };
  };

  const lines = [];
  const push = (t) => lines.push(t);

  // No task framing here ("help me sharpen this...") — that primes the LLM to
  // treat the brief as a rough draft to critique/rewrite, which can make an
  // already-personalized brief read back as generic. Just the labeled data;
  // the rep supplies their own question when they paste this in.
  push(`# Game Day Brief — ${dash(prep.prospect)}`);
  push("");

  // ---- seller profile (the exact baseline this brief was generated against) ----
  const settings = (typeof MP !== "undefined" && MP.getSettings) ? MP.getSettings() : null;
  if (settings && typeof MP.buildSystemPrompt === "function") {
    push("<seller_profile>");
    push("_Reference only — the seller's company & ICP profile this brief was generated against. Not a role for you to assume._");
    push("");
    const full = MP.buildSystemPrompt(settings);
    const start = full.indexOf("# WHO I AM");
    const end = full.indexOf("# INSTRUCTIONS");
    const mid = (start !== -1 && end !== -1) ? full.slice(start, end).trim() : full.trim();
    // The source headers are shouty ALL-CAPS ("# WHO I AM") to stand out inside a
    // system prompt; sentence-case them to match this doc's other headers.
    const toSentenceCase = (t) => t.toLowerCase().replace(/\bi\b/g, "I").replace(/^./, (c) => c.toUpperCase());
    push(mid.replace(/^# (.+)$/gm, (_m, t) => `## ${toSentenceCase(t)}`));
    push("</seller_profile>");
    push("");
  }

  // ---- the brief itself ----
  push("<game_day_brief>");
  const metaBits = [];
  if (oneLine(prep.prospect)) metaBits.push(`**Prospect:** ${oneLine(prep.prospect)}`);
  if (oneLine(prep.stage)) metaBits.push(`**Stage:** ${oneLine(prep.stage)} call`);
  if (oneLine(d.confidence)) metaBits.push(`**Confidence:** ${oneLine(d.confidence).replace(/^./, (c) => c.toUpperCase())}`);
  const prepped = fmtDate(prep.createdAt);
  if (prepped) metaBits.push(`**Prepared:** ${prepped}`);
  if (metaBits.length) { push(metaBits.join(" · ")); push(""); }

  if (oneLine(d.story)) {
    push("## The story");
    push(oneLine(d.story));
    if (Array.isArray(d.signals) && d.signals.length) {
      const sig = d.signals.map(oneLine).filter(Boolean).join(" · ");
      if (sig) { push(""); push(`**Signals:** ${sig}`); }
    }
    push("");
  }

  if (d.gameplan && (oneLine(d.gameplan.verdict) || oneLine(d.gameplan.say))) {
    push("## 30-second game plan");
    if (oneLine(d.gameplan.verdict)) push(`**${oneLine(d.gameplan.verdict)}**`);
    if (oneLine(d.gameplan.say)) push(`- **Say:** ${oneLine(d.gameplan.say)}`);
    if (oneLine(d.gameplan.prove)) push(`- **Prove:** ${oneLine(d.gameplan.prove)}`);
    if (oneLine(d.gameplan.ask)) push(`- **Ask:** ${oneLine(d.gameplan.ask)}`);
    if (oneLine(d.gameplan.watch)) push(`- **Watch for:** ${oneLine(d.gameplan.watch)}`);
    push("");
  }

  if (d.fit && Array.isArray(d.fit.points) && d.fit.points.length) {
    push(`## Why they fit ${dash(d.fit.product)}`);
    if (oneLine(d.fit.verdict)) push(`**${oneLine(d.fit.verdict)}**`);
    d.fit.points.forEach((p) => { if (oneLine(p)) push(`- ${oneLine(p)}`); });
    push("");
  }

  if (Array.isArray(d.findings) && d.findings.length) {
    push("## What the research found");
    d.findings.forEach((f) => {
      const t = oneLine(f && f.text);
      if (t) push(`- ${t}${f.src ? ` _(Source: ${oneLine(f.src)})_` : ""}`);
    });
    push("");
  }

  if (Array.isArray(d.agenda) && d.agenda.length) {
    push("## Suggested agenda");
    d.agenda.forEach((a) => {
      const label = oneLine(a && a.label);
      if (!label) return;
      const time = oneLine(a.time);
      push(`- ${time ? `**${time}** ` : ""}${label}${a.detail ? ` — ${oneLine(a.detail)}` : ""}`);
    });
    push("");
  }

  if (Array.isArray(d.pitch) && d.pitch.length) {
    push("## Pitch points");
    d.pitch.forEach((p, i) => {
      const h = oneLine(p && p.headline);
      if (!h) return;
      push(`${i + 1}. **${h}**${p.body ? ` — ${oneLine(p.body)}` : ""}`);
      if (p.why) push(`   _Why it lands: ${oneLine(p.why)}_`);
    });
    push("");
  }

  if (Array.isArray(d.questions) && d.questions.length) {
    push("## Questions to ask");
    d.questions.forEach((q, i) => { const t = oneLine(q); if (t) push(`${i + 1}. ${t}`); });
    push("");
  }

  if (Array.isArray(d.objections) && d.objections.length) {
    push("## Likely objections");
    d.objections.forEach((o) => {
      const q = oneLine(o && o.q);
      if (!q) return;
      const a = oneLine(o.a);
      push(`- **"${q}"**${a ? ` — ${a}` : ""}`);
    });
    push("");
  }

  if (Array.isArray(d.stakeholders) && d.stakeholders.length) {
    push("## Who's in the room");
    d.stakeholders.forEach((p) => {
      const name = oneLine(p && p.name);
      if (!name) return;
      let line = `- **${name}${p.title ? `, ${oneLine(p.title)}` : ""}**`;
      if (p.kind) line += ` (${oneLine(p.kind)})`;
      if (p.angle) line += `: ${oneLine(p.angle)}`;
      push(line);
    });
    push("");
  }

  const hasTeam = Array.isArray(d.team) && d.team.length;
  const soloFitText = d.soloFit && oneLine(d.soloFit.text);
  if (hasTeam || soloFitText) {
    push("## Roles to consider bringing");
    if (hasTeam) d.team.forEach((t) => { if (t && t.role) push(`- **${oneLine(t.role)}** — ${oneLine(t.reason)}`); });
    if (soloFitText) {
      if (hasTeam) push("");
      push(`_${d.soloFit.kind === "escalate" ? "Heads up" : "Going solo"}: ${soloFitText}_`);
    }
    push("");
  }

  const sources = buildSources(prep.meta && prep.meta.sources);
  if (sources.shown.length) {
    push("## Sources");
    sources.shown.forEach((s, i) => push(`${i + 1}. ${s}`));
    if (sources.more > 0) { push(""); push(`_+ ${sources.more} more sources consulted during research._`); }
    push("");
  }

  push("</game_day_brief>");

  return lines.join("\n").replace(/\n{3,}/g, "\n\n").trim();
}

Object.assign(window, { PrepViewPage, BriefFeedback, Substat, Objection, TeamRecommender, DEPARTMENTS, buildBriefMarkdown });
