// GENERATE from scratch — multi-input + AI options + results
function GeneratePage({ onOpenTemplate, aiAllowed = true, onSignIn }) {
  const [step, setStep] = useState("input"); // input | options | generating | results
  const [inputMode, setInputMode] = useState("text"); // text | url | notion | upload
  const [brief, setBrief] = useState("");
  const [url, setUrl] = useState("");
  const [attachments, setAttachments] = useState([]); // [{ name, isImage }], max 5
  const [outputType, setOutputType] = useState("carousel-linkedin");
  const [variations, setVariations] = useState(3);
  const [tone, setTone] = useState("confident");
  const [slideCount, setSlideCount] = useState(10);
  const [generatedSet, setGeneratedSet] = useState([]);

  const [genError, setGenError] = useState(null);
  const [signInAlert, setSignInAlert] = useState(false);
  const signInBannerRef = useRef(null);
  const [signingIn, setSigningIn] = useState(false);

  const nudgeSignIn = () => {
    signInBannerRef.current?.scrollIntoView({ behavior: "smooth", block: "center" });
    setSignInAlert(true);
    window.clearTimeout(nudgeSignIn._t);
    nudgeSignIn._t = window.setTimeout(() => setSignInAlert(false), 650);
  };

  const handleSignIn = async () => {
    if (signingIn || !onSignIn) return;
    setSigningIn(true);
    try {
      await onSignIn();
      // Success navigates away via the OAuth redirect — stay in the
      // loading state rather than resetting (see sidebar.jsx's signIn).
    } catch (e) {
      setSigningIn(false);
    }
  };

  const MAX_FILES = 5;
  const addFiles = (fileList) => {
    const incoming = Array.from(fileList || []).map((f) => ({
      name: f.name,
      isImage: /^image\//.test(f.type) || /\.(png|jpe?g|gif|webp|svg)$/i.test(f.name),
      file: f, // keep the raw File so we can upload it on generate
    }));
    setAttachments((prev) => [...prev, ...incoming].slice(0, MAX_FILES));
  };
  const removeFile = (idx) => setAttachments((prev) => prev.filter((_, i) => i !== idx));

  const canProceedToOptions = () => {
    if (inputMode === "text") return brief.trim().length > 20 || attachments.length > 0;
    if (inputMode === "url" || inputMode === "notion") return url.trim().startsWith("http") || attachments.length > 0;
    if (inputMode === "upload") return attachments.length > 0;
    return false;
  };

  const handleGenerate = async () => {
    // Password-only users can see this flow but not run it.
    if (!aiAllowed) { onSignIn && onSignIn(); return; }
    setStep("generating");
    setGenError(null);
    try {
      // Upload any attached files first so the backend can reference them.
      let uploadMeta = [];
      const withFiles = attachments.filter((a) => a.file);
      if (withFiles.length) {
        const { uploads } = await API.upload(withFiles.map((a) => a.file));
        uploadMeta = uploads.map((u) => ({ original: u.original, url: u.url, isImage: u.isImage }));
      }

      const { variants } = await API.generate({
        outputType,
        brief,
        url,
        inputMode,
        tone,
        variations,
        slideCount,
        attachments: uploadMeta.length
          ? uploadMeta
          : attachments.map((a) => ({ original: a.name, isImage: a.isImage })),
      });

      setGeneratedSet(variants);
      setStep("results");
    } catch (err) {
      console.error("Generation failed:", err);
      setGenError(err.message || "Generation failed");
      // SSO-only: don't fall back to the mock — the user needs to sign in.
      if (/sign in/i.test(err.message || "")) {
        setStep("input");
        return;
      }
      // The server already falls back to on-brand output when the AI call
      // fails, so reaching here means a real request error (network/500).
      // Surface it instead of faking a result from an unrelated template —
      // that "random carousel" behavior was confusing and wrong.
      setGenError(err.message || "Generation failed. Please try again.");
      setStep("input");
    }
  };

  if (step === "generating") {
    return <GeneratingState />;
  }
  if (step === "results") {
    return (
      <ResultsView
        variants={generatedSet}
        onPick={onOpenTemplate}
        onRegenerate={() => setStep("options")}
        onStartOver={() => setStep("input")}
      />
    );
  }
  if (step === "options") {
    return (
      <OptionsStep
        outputType={outputType} setOutputType={setOutputType}
        variations={variations} setVariations={setVariations}
        tone={tone} setTone={setTone}
        slideCount={slideCount} setSlideCount={setSlideCount}
        onBack={() => setStep("input")}
        onGenerate={handleGenerate}
        brief={brief}
        aiAllowed={aiAllowed}
        onSignIn={onSignIn}
      />
    );
  }

  // INPUT step
  return (
    <div className="fade-in">
      <div className="eyebrow">GENERATE FROM SCRATCH</div>
      <h1 className="page-title">
        Brief in. Carousel out.
      </h1>
      <p className="page-subtitle">
        Notion brief, raw link, file upload, or a few sentences. AI generates a fully editable, on-brand asset in your Flexxi kit.
      </p>

      {!aiAllowed && (
        <div
          ref={signInBannerRef}
          className={signInAlert ? "shake" : ""}
          style={{
            marginTop: 24, padding: "16px 18px", borderRadius: 14,
            background: "rgba(172,85,255,0.10)",
            border: signInAlert ? "1px solid var(--ink)" : "1px solid var(--line)",
            display: "flex", alignItems: "center", gap: 14,
            transition: "border-color 200ms ease",
          }}
        >
          <div style={{ width: 38, height: 38, flexShrink: 0, background: "var(--ink)", color: "var(--surface)", borderRadius: 10, display: "grid", placeItems: "center" }}>
            <Icons.Sparkle size={18} />
          </div>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontFamily: "var(--font-display)", fontWeight: 600, fontSize: 15.5 }}>AI generation needs sign-in</div>
            <div style={{ fontSize: 13, color: "var(--ink-2)", lineHeight: 1.45 }}>
              You can explore the templates and editor with the team password. To generate from a brief, sign in with your Flexxi Google account.
            </div>
          </div>
          <button className="btn btn-primary" style={{ flexShrink: 0 }} onClick={handleSignIn} disabled={signingIn}>
            {signingIn ? <span className="spinner" style={{ width: 13, height: 13 }} /> : null} Sign in with Google
          </button>
        </div>
      )}

      {genError && (
        <div style={{ marginTop: 20, padding: "12px 16px", borderRadius: 12, background: "rgba(172,85,255,0.10)", border: "1px solid var(--line)", color: "var(--ink-2)", fontSize: 13.5 }}>
          {genError}
        </div>
      )}

      {/* INPUT TABS */}
      <div style={{ marginTop: 40 }}>
        <div className="gen-tab-row">
          <button className={`gen-tab ${inputMode === "text" ? "active" : ""}`} onClick={() => setInputMode("text")}>
            <Icons.Text size={13} style={{ marginRight: 6, verticalAlign: "-2px" }} />
            Type a brief
          </button>
          <button className={`gen-tab ${inputMode === "notion" ? "active" : ""}`} onClick={() => setInputMode("notion")}>
            <Icons.Notion size={13} style={{ marginRight: 6, verticalAlign: "-2px" }} />
            From Notion
          </button>
          <button className={`gen-tab ${inputMode === "url" ? "active" : ""}`} onClick={() => setInputMode("url")}>
            <Icons.Link size={13} style={{ marginRight: 6, verticalAlign: "-2px" }} />
            Paste URL
          </button>
          <button className={`gen-tab ${inputMode === "upload" ? "active" : ""}`} onClick={() => setInputMode("upload")}>
            <Icons.Upload size={13} style={{ marginRight: 6, verticalAlign: "-2px" }} />
            Upload
          </button>
        </div>

        <div className="card" style={{ marginTop: 16, padding: 28 }}>
          {inputMode === "text" && (
            <>
              <label className="eyebrow" style={{ marginBottom: 10, display: "block" }}>YOUR IDEA</label>
              <textarea
                className="input"
                placeholder={"e.g. We want a 10-slide carousel announcing our new AI features. Audience: marketing leads. Key points: it's faster, on-brand by default, no design work needed. End with a 'book a call' CTA."}
                value={brief}
                onChange={(e) => setBrief(e.target.value)}
                style={{ minHeight: 200, fontSize: 15, lineHeight: 1.5 }}
              />
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: 10, fontSize: 12, color: "var(--ink-3)" }}>
                <div>The more you give, the better it gets. Aim for 3–5 sentences.</div>
                <div>{brief.length} chars</div>
              </div>
            </>
          )}
          {inputMode === "notion" && (
            <>
              <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 14 }}>
                <div style={{ width: 44, height: 44, background: "#070707", color: "white", borderRadius: 10, display: "grid", placeItems: "center" }}>
                  <Icons.Notion size={22} />
                </div>
                <div>
                  <div style={{ fontFamily: "var(--font-display)", fontWeight: 600, fontSize: 18 }}>Paste a Notion page</div>
                  <div style={{ fontSize: 12, color: "var(--ink-3)" }}>We'll read the page and design around it. Share the page with the Flexxi integration first.</div>
                </div>
              </div>
              <input
                className="input"
                placeholder="https://www.notion.so/your-workspace/Page-Title-abc123…"
                value={url}
                onChange={(e) => setUrl(e.target.value)}
                style={{ fontSize: 14 }}
              />
              <p style={{ fontSize: 12, color: "var(--ink-3)", marginTop: 10 }}>
                Tip: in Notion, open the page → ••• → Connections → add the Flexxi integration so we can read it.
              </p>
            </>
          )}
          {inputMode === "url" && (
            <>
              <label className="eyebrow" style={{ marginBottom: 10, display: "block" }}>SOURCE URL</label>
              <input
                className="input"
                placeholder="https://yourblog.com/post-title"
                value={url}
                onChange={(e) => setUrl(e.target.value)}
                style={{ fontSize: 14 }}
              />
              <p style={{ fontSize: 12, color: "var(--ink-3)", marginTop: 10 }}>
                Works with blog posts, Google Docs (shared), case studies, even tweets.
              </p>
            </>
          )}
          {inputMode === "upload" && (
            <>
              <label
                style={{
                  display: "block",
                  padding: 40,
                  border: "2px dashed var(--line-2)",
                  borderRadius: 16,
                  textAlign: "center",
                  cursor: attachments.length >= MAX_FILES ? "not-allowed" : "pointer",
                  background: "var(--bg)",
                  opacity: attachments.length >= MAX_FILES ? 0.5 : 1,
                  transition: "border-color 120ms ease, background 120ms ease",
                }}
                onDragOver={(e) => e.preventDefault()}
                onDrop={(e) => { e.preventDefault(); addFiles(e.dataTransfer.files); }}
              >
                <input type="file" multiple accept="*/*" style={{ display: "none" }} disabled={attachments.length >= MAX_FILES} onChange={(e) => addFiles(e.target.files)} />
                <Icons.Upload size={32} />
                <div style={{ fontFamily: "var(--font-display)", fontSize: 22, fontWeight: 600, marginTop: 14, letterSpacing: "-0.02em" }}>
                  {attachments.length >= MAX_FILES ? "Maximum 5 files" : "Drop files here"}
                </div>
                <div style={{ fontSize: 13, color: "var(--ink-3)", marginTop: 6 }}>
                  .md · .txt · .docx · .pdf · or any image — up to 5
                </div>
              </label>
            </>
          )}

          {/* SHARED ATTACHMENTS — available in every input mode */}
          <AttachmentBar
            attachments={attachments}
            max={MAX_FILES}
            onAdd={addFiles}
            onRemove={removeFile}
            hideButton={inputMode === "upload"}
          />
        </div>

        {/* PROCEED */}
        <div style={{ marginTop: 24, display: "flex", justifyContent: "flex-end", gap: 12 }}>
          <button className="btn btn-ghost" disabled>
            <Icons.Sparkle size={13} /> Try an example
          </button>
          <button
            className={`btn btn-primary btn-lg ${signInAlert ? "shake" : ""}`}
            disabled={!canProceedToOptions()}
            style={{ opacity: canProceedToOptions() && aiAllowed ? 1 : 0.4 }}
            onClick={() => {
              if (!aiAllowed) { nudgeSignIn(); return; }
              setStep("options");
            }}
          >
            Next: pick output <Icons.ArrowRight size={14} />
          </button>
        </div>

        {/* SUGGESTIONS */}
        <div style={{ marginTop: 56 }}>
          <h2 className="section-title" style={{ fontSize: 18 }}>Or try a prompt</h2>
          <div className="grid-3" style={{ marginTop: 14 }}>
            {[
              "10-slide Instagram carousel: 'How we redesigned onboarding'",
              "Spotify cover for episode 14, guest: Allie Vogel",
              "LinkedIn carousel announcing our $4M seed round",
            ].map((p) => (
              <button
                key={p}
                onClick={() => { setInputMode("text"); setBrief(p); }}
                className="card hover-card"
                style={{ padding: 18, textAlign: "left", cursor: "pointer", background: "var(--surface)" }}
              >
                <div style={{ display: "flex", alignItems: "flex-start", gap: 10 }}>
                  <Icons.Sparkle size={16} />
                  <div style={{ fontSize: 13.5, color: "var(--ink-2)", lineHeight: 1.45 }}>{p}</div>
                </div>
              </button>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

// =============================================================
// AttachmentBar — shared across every input mode. Add files or
// images (up to `max`), shown as removable chips.
// =============================================================
function AttachmentBar({ attachments, max, onAdd, onRemove, hideButton }) {
  const full = attachments.length >= max;
  const fileRef = React.useRef(null);
  return (
    <div style={{ marginTop: attachments.length || !hideButton ? 16 : 0 }}>
      {attachments.length > 0 && (
        <div style={{ display: "flex", flexWrap: "wrap", gap: 8, marginBottom: hideButton ? 0 : 12 }}>
          {attachments.map((a, i) => (
            <div
              key={a.name + i}
              style={{
                display: "inline-flex", alignItems: "center", gap: 8,
                padding: "6px 8px 6px 10px", background: "var(--surface)",
                border: "1px solid var(--line)", borderRadius: 10, fontSize: 12.5,
                color: "var(--ink-2)", maxWidth: 220,
              }}
            >
              {a.isImage ? <Icons.Image size={14} /> : <Icons.File size={14} />}
              <span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{a.name}</span>
              <button
                onClick={() => onRemove(i)}
                aria-label={`Remove ${a.name}`}
                style={{ display: "grid", placeItems: "center", width: 18, height: 18, border: "none", background: "transparent", cursor: "pointer", color: "var(--ink-3)", flexShrink: 0, padding: 0 }}
              >
                <Icons.X size={13} />
              </button>
            </div>
          ))}
        </div>
      )}
      {!hideButton && (
        <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
          <button
            className="btn btn-ghost btn-sm"
            disabled={full}
            style={{ opacity: full ? 0.4 : 1 }}
            onClick={() => fileRef.current && fileRef.current.click()}
          >
            <Icons.Plus size={13} /> Attach files or images
          </button>
          <span style={{ fontSize: 11.5, color: "var(--ink-3)" }}>
            {full ? "Maximum 5 files" : `${attachments.length}/${max} · images & docs welcome`}
          </span>
          <input
            ref={fileRef}
            type="file"
            multiple
            accept="*/*"
            style={{ display: "none" }}
            onChange={(e) => { onAdd(e.target.files); e.target.value = ""; }}
          />
        </div>
      )}
    </div>
  );
}

// =============================================================
// Step 2: OPTIONS
// =============================================================
function OptionsStep({ outputType, setOutputType, variations, setVariations, tone, setTone, slideCount, setSlideCount, onBack, onGenerate, brief, aiAllowed = true, onSignIn }) {
  const outputs = [
    { id: "carousel-linkedin", label: "Carousel", desc: "1080×1350 · multi-slide", icon: "Linkedin" },
    { id: "instagram-post", label: "Instagram Post", desc: "1080×1350 portrait", icon: "Instagram" },
    { id: "social-square", label: "Social media 1:1", desc: "1080×1080 square", icon: "Grid" },
    { id: "podcast-youtube", label: "YouTube Cover", desc: "1280×720 thumbnail", icon: "Youtube" },
  ];
  const tones = [
    { id: "confident", label: "Confident", desc: "Direct, declarative, no hedging" },
    { id: "playful", label: "Playful", desc: "Lighter rhythm, stickers, winks" },
    { id: "editorial", label: "Editorial", desc: "Serif italics, longer thoughts" },
    { id: "punchy", label: "Punchy", desc: "Short. Sharp. Stop scrolling." },
  ];

  return (
    <div className="fade-in">
      <button className="btn btn-ghost btn-sm" onClick={onBack} style={{ marginBottom: 16 }}>
        <Icons.ArrowLeft size={13} /> Back to brief
      </button>
      <div className="eyebrow">STEP 2 OF 2</div>
      <h1 className="page-title">
        Pick the output.
      </h1>
      <p className="page-subtitle">
        Choose the format, tone, and how many variations to generate. We'll do the rest.
      </p>

      {/* OUTPUT TYPE */}
      <section style={{ marginTop: 40 }}>
        <h2 className="section-title" style={{ fontSize: 18, marginBottom: 14 }}>Format</h2>
        <div className="grid-4">
          {outputs.map((o) => {
            const Icon = Icons[o.icon];
            return (
              <button
                key={o.id}
                className={`option-card ${outputType === o.id ? "selected" : ""}`}
                onClick={() => setOutputType(o.id)}
                style={{ textAlign: "left" }}
              >
                <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 10 }}>
                  <div style={{ width: 32, height: 32, background: "var(--bg)", borderRadius: 8, display: "grid", placeItems: "center" }}>
                    <Icon size={16} />
                  </div>
                  {outputType === o.id && <div className="pill dark" style={{ marginLeft: "auto" }}>Selected</div>}
                </div>
                <div className="option-card-title">{o.label}</div>
                <div className="option-card-desc">{o.desc}</div>
              </button>
            );
          })}
        </div>
      </section>

      {/* SLIDES — carousels only */}
      {outputType === "carousel-linkedin" && (
        <section style={{ marginTop: 40 }}>
          <h2 className="section-title" style={{ fontSize: 18, marginBottom: 14 }}>Slides</h2>
          <div className="grid-4">
            {[4, 6, 8, 10].map((n) => (
              <button
                key={n}
                className={`option-card ${slideCount === n ? "selected" : ""}`}
                onClick={() => setSlideCount(n)}
                style={{ textAlign: "left" }}
              >
                <div style={{ fontFamily: "var(--font-display)", fontSize: 36, fontWeight: 700, letterSpacing: "-0.025em" }}>{n}</div>
                <div className="option-card-desc" style={{ marginTop: 6 }}>{n} slides</div>
              </button>
            ))}
          </div>
        </section>
      )}

      {/* TONE */}
      <section style={{ marginTop: 40 }}>
        <h2 className="section-title" style={{ fontSize: 18, marginBottom: 14 }}>Tone</h2>
        <div className="grid-4">
          {tones.map((t) => (
            <button
              key={t.id}
              className={`option-card ${tone === t.id ? "selected" : ""}`}
              onClick={() => setTone(t.id)}
              style={{ textAlign: "left" }}
            >
              <div className="option-card-title">{t.label}</div>
              <div className="option-card-desc">{t.desc}</div>
            </button>
          ))}
        </div>
      </section>

      {/* VARIATIONS */}
      <section style={{ marginTop: 40 }}>
        <h2 className="section-title" style={{ fontSize: 18, marginBottom: 14 }}>Variations</h2>
        <div className="grid-3">
          {[
            { v: 1, label: "Just one", desc: "Skip the picker, jump to editing." },
            { v: 3, label: "Three", desc: "Compare and pick a direction." },
            { v: 5, label: "Five", desc: "Maximum exploration." },
          ].map((opt) => (
            <button
              key={opt.v}
              className={`option-card ${variations === opt.v ? "selected" : ""}`}
              onClick={() => setVariations(opt.v)}
              style={{ textAlign: "left" }}
            >
              <div style={{ fontFamily: "var(--font-display)", fontSize: 36, fontWeight: 700, letterSpacing: "-0.025em" }}>
                {opt.v}
              </div>
              <div className="option-card-title" style={{ marginTop: 6 }}>{opt.label}</div>
              <div className="option-card-desc">{opt.desc}</div>
            </button>
          ))}
        </div>
      </section>

      {/* BRIEF PREVIEW */}
      <section style={{ marginTop: 40 }}>
        <h2 className="section-title" style={{ fontSize: 18, marginBottom: 14 }}>Your brief</h2>
        <div className="card" style={{ padding: 18, background: "var(--surface)" }}>
          <p style={{ margin: 0, fontFamily: "var(--font-ui)", fontSize: 15, lineHeight: 1.55, color: "var(--ink-2)" }}>
            {brief || "—"}
          </p>
        </div>
      </section>

      <div style={{ marginTop: 32, display: "flex", justifyContent: "flex-end", alignItems: "center", gap: 14 }}>
        {aiAllowed ? (
          <button className="btn btn-primary btn-lg" onClick={onGenerate}>
            <Icons.Wand size={14} /> Generate {variations} variation{variations === 1 ? "" : "s"}
          </button>
        ) : (
          <>
            <span style={{ fontSize: 13, color: "var(--ink-3)" }}>
              Sign in to generate — preview the options freely.
            </span>
            <button className="btn btn-primary btn-lg" onClick={() => onSignIn && onSignIn()}>
              <Icons.Sparkle size={14} /> Sign in with Google
            </button>
          </>
        )}
      </div>
    </div>
  );
}

// =============================================================
// Generating state
// =============================================================
function GeneratingState() {
  const steps = [
    "Reading your brief...",
    "Pulling from brand foundations...",
    "Laying out slides...",
    "Polishing copy...",
  ];
  const [stepIdx, setStepIdx] = useState(0);
  useEffect(() => {
    const id = setInterval(() => setStepIdx((i) => Math.min(i + 1, steps.length - 1)), 550);
    return () => clearInterval(id);
  }, []);
  return (
    <div style={{ minHeight: "70vh", display: "grid", placeItems: "center" }} className="fade-in">
      <div style={{ textAlign: "center", maxWidth: 540 }}>
        <div style={{ display: "inline-flex", padding: 18, background: "var(--ink)", borderRadius: 999, color: "var(--surface)", marginBottom: 32, position: "relative" }}>
          <Icons.Sparkle size={36} />
          <div style={{ position: "absolute", inset: -8, border: "2px dashed var(--ink)", borderRadius: 999, animation: "spin 8s linear infinite", opacity: 0.2 }}></div>
        </div>
        <h2 style={{ fontFamily: "var(--font-display)", fontSize: 56, fontWeight: 700, letterSpacing: "-0.035em", lineHeight: 0.95, margin: 0 }}>
          Generating your<br />variations.
        </h2>
        <div style={{ marginTop: 32, display: "flex", flexDirection: "column", gap: 10, alignItems: "flex-start", textAlign: "left", maxWidth: 360, margin: "32px auto 0" }}>
          {steps.map((s, i) => (
            <div key={s} style={{ display: "flex", alignItems: "center", gap: 10, opacity: i <= stepIdx ? 1 : 0.35, transition: "opacity 200ms ease" }}>
              {i < stepIdx ? (
                <div style={{ width: 18, height: 18, borderRadius: 999, background: "var(--green)", display: "grid", placeItems: "center" }}>
                  <Icons.Check size={12} />
                </div>
              ) : i === stepIdx ? (
                <div className="spinner" style={{ color: "var(--ink)" }}></div>
              ) : (
                <div style={{ width: 18, height: 18, borderRadius: 999, background: "var(--line)" }}></div>
              )}
              <span style={{ fontSize: 14, color: "var(--ink-2)" }}>{s}</span>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

// =============================================================
// Generate variations from a base template
// =============================================================
function generateVariations(base, brief, count) {
  // Extract a "headline" from the brief
  const sentences = brief.split(/[.!?]/).map(s => s.trim()).filter(Boolean);
  const main = sentences[0] || "Your story, your way";
  // Make N variations differing by background + headline phrasing
  const palettes = [
    { bg: "#070707", accent: "#FFFFFF", emphasis: "#E9E9F0" },
    { bg: "#E9E9F0", accent: "#070707", emphasis: "white" },
    { bg: "#FFFFFF", accent: "#070707", emphasis: "#070707" },
    { bg: "#070707", accent: "#E9E9F0", emphasis: "white" },
    { bg: "#FFFFFF", accent: "#383838", emphasis: "#E9E9F0" },
  ];
  const headlines = [
    main,
    sentences[1] || main,
    `What if ${main.toLowerCase()}?`,
    `${main}.\nReally.`,
    main.replace(/we /gi, "you "),
  ];

  return Array.from({ length: count }).map((_, i) => {
    const p = palettes[i % palettes.length];
    const headline = headlines[i % headlines.length].slice(0, 80);
    const variant = JSON.parse(JSON.stringify(base));
    variant.id = `gen-${i}-${Date.now()}`;
    variant.name = `${base.name} — V${i + 1}`;
    // Mutate first slide
    if (variant.slides[0]) {
      variant.slides[0].background = p.bg;
      const titleEl = variant.slides[0].elements.find(e => e.type === "text" && e.content && e.content.length > 5 && e.fontSize > 60);
      if (titleEl) {
        titleEl.content = headline;
        titleEl.color = p.accent;
      }
    }
    // Tweak other slides' background subtly
    variant.slides.forEach((s, idx) => {
      if (idx === 0) return;
      if (idx % 3 === (i % 3)) {
        s.background = p.bg;
        s.elements.forEach(e => {
          if (e.type === "text" && (e.color === "#070707" || e.color === "#383838")) {
            if (p.bg === "#070707") e.color = "#FFFFFF";
          }
        });
      }
    });
    return variant;
  });
}

// =============================================================
// Results view
// =============================================================
function ResultsView({ variants, onPick, onRegenerate, onStartOver }) {
  return (
    <div className="fade-in">
      <button className="btn btn-ghost btn-sm" onClick={onStartOver} style={{ marginBottom: 16 }}>
        <Icons.ArrowLeft size={13} /> Start over
      </button>
      <div className="eyebrow">YOUR VARIATIONS</div>
      <h1 className="page-title">
        Pick a direction.
      </h1>
      <p className="page-subtitle">
        Each one is fully editable. Click to open in the editor — change anything, ship it.
      </p>

      <div className="grid-3" style={{ marginTop: 32 }}>
        {variants.map((v, i) => (
          <div key={v.id} className="card hover-card" style={{ padding: 14 }} onClick={() => onPick(v)}>
            <div style={{ position: "relative" }}>
              <TemplateThumbnail template={v} />
              <div className="sticker" style={{ position: "absolute", top: 10, left: 10, background: "#070707", color: "#FFFFFF", fontSize: 11 }}>
                V{i + 1}
              </div>
            </div>
            <div style={{ padding: "14px 6px 4px", display: "flex", justifyContent: "space-between", alignItems: "center" }}>
              <div>
                <div style={{ fontFamily: "var(--font-display)", fontSize: 15, fontWeight: 600 }}>Variation {i + 1}</div>
                <div style={{ fontSize: 11.5, color: "var(--ink-3)" }}>{v.slides.length} slides · click to edit</div>
              </div>
              <Icons.ArrowRight size={14} />
            </div>
          </div>
        ))}
      </div>

      <div style={{ marginTop: 32, display: "flex", justifyContent: "center", gap: 12 }}>
        <button className="btn btn-ghost" onClick={onRegenerate}>
          <Icons.Sparkle size={13} /> Regenerate
        </button>
        <button className="btn btn-ghost" onClick={onStartOver}>
          New brief
        </button>
      </div>
    </div>
  );
}

window.GeneratePage = GeneratePage;
