/* SpeakMind — HeroShowcase: a real app window receiving dictated text,
   with the floating overlay docked over it. Shared one-cycle state machine. */

/* ---- shared demo cycle: idle → listening → processing → inserted ---- */
function useDemoCycle(onChange) {
  const [idx, setIdx] = useState(0);
  const [phase, setPhase] = useState("idle");
  const [wc, setWc] = useState(0);
  const timers = useRef([]);
  const paused = useRef(false);
  const demo = window.SM.demos[idx];
  const words = window.SM.t(demo.raw).split(" ");

  useEffect(() => { if (onChange) onChange(demo, phase); }, [idx, phase]);

  useEffect(() => {
    const add = (fn, ms) => timers.current.push(setTimeout(fn, ms));
    timers.current.forEach(clearTimeout); timers.current = [];
    setPhase("idle"); setWc(0);
    add(() => {
      setPhase("listening");
      // slower word reveal so the spoken input is readable
      const per = Math.max(115, Math.min(175, 2700 / words.length));
      words.forEach((_, i) => add(() => setWc(i + 1), per * (i + 1)));
      const lend = per * words.length + 850;
      add(() => setPhase("processing"), lend);
      // longer "processing" so the state registers; long result hold so the
      // finished text is actually readable before the next demo
      add(() => setPhase("inserted"), lend + 1600);
      // hold on the finished result; if the user is hovering (reading), wait
      // until they move away before advancing to the next demo
      const advance = () => {
        if (paused.current) { timers.current.push(setTimeout(advance, 500)); }
        else { setIdx((d) => (d + 1) % window.SM.demos.length); }
      };
      add(advance, lend + 1600 + 7000);
    }, 900);
    return () => { timers.current.forEach(clearTimeout); timers.current = []; };
  }, [idx]);

  return { demo, phase, words: words.slice(0, wc), idx, paused };
}

/* ---- per-app document skins (receive the inserted text) ---- */
function NotionDoc({ demo, inserted }) {
  const { RichText } = window.SMOverlay;
  const t = window.SM.t;
  let liN = 0;
  return (
    <div className={"sc-pad" + (inserted ? " inserted" : "")}>
      <div className="nt-crumb">◳ {t("Workspace")} <span>/</span> {t("Product")} <span>/</span> {t("Notes")}</div>
      {inserted ? (
        <>
          <div className="nt-title ins ins-1">{t(demo.result.title || "New note")}</div>
          <div className="nt-body">
            {demo.result.blocks.map((b, i) => {
              if (b.t === "p") return <p key={i} className={`ins ins-${i + 2}`}><RichText text={t(b.v)} /></p>;
              if (b.t === "h") return <h4 key={i} className={`ins ins-${i + 2}`}>{t(b.v)}</h4>;
              if (b.t === "li") { liN++; return <ul key={i} className={`ins ins-${i + 2}`}><li><span className="chk" /><span><RichText text={t(b.v)} /></span></li></ul>; }
              return null;
            })}
          </div>
        </>
      ) : (
        <>
          <div className="nt-title" style={{ color: "var(--text-faint)" }}>{t("Untitled")}<span className="doc-caret" /></div>
          <div className="nt-body" style={{ color: "var(--text-faint)", fontSize: "14px" }}><p>{t("Empty page — start dictating.")}</p></div>
        </>
      )}
    </div>
  );
}

function CursorEditor({ demo, inserted }) {
  const t = window.SM.t;
  const placeholder = "// " + t("awaiting dictation…");
  const lines = inserted ? demo.result.code.split("\n") : [placeholder];
  const hl = (s) => window.SMOverlay.highlightSwift ? window.SMOverlay.highlightSwift(s) : s;
  return (
    <div className={"sc-app cs-app sc-pad" + (inserted ? " inserted" : "")} style={{ position: "absolute", inset: 0, overflow: "hidden" }}>
      {lines.map((ln, i) => (
        <div className="cs-gutter-row" key={i}>
          <span className="cs-ln">{i + 1}</span>
          <span className={"cs-code" + (inserted ? ` ins ins-${Math.min(i + 1, 6)}` : "")}
            dangerouslySetInnerHTML={{ __html: inserted ? hl(ln || " ") : '<span style="color:rgba(242,232,224,.3)">' + placeholder + '</span>' }} />
        </div>
      ))}
    </div>
  );
}

function GmailCompose({ demo, inserted }) {
  const t = window.SM.t;
  return (
    <div className={"sc-pad" + (inserted ? " inserted" : "")}>
      <div className="gm-head">{t("New message")}</div>
      <div className="gm-field"><span className="lab">{t("To")}</span><span className="val">team@kanverse.io</span></div>
      <div className="gm-field"><span className="lab">{t("Subject")}</span><span className="val">{t(demo.result.subject)}</span></div>
      <div className={"gm-body" + (inserted ? " ins ins-1" : "")}>{inserted ? t(demo.result.body) : t("Compose…")}</div>
    </div>
  );
}

function ChatGPTInput({ demo, inserted }) {
  const t = window.SM.t;
  return (
    <div className={"sc-app gpt-app sc-pad" + (inserted ? " inserted" : "")} style={{ position: "absolute", inset: 0 }}>
      {inserted ? (
        <div className="gpt-msg ins ins-1">
          {demo.result.rows.map((r, i) => (
            <div className="gpt-prompt-row" key={i}><span className="k">{t(r.k)}</span><span className="v">{t(r.v)}</span></div>
          ))}
        </div>
      ) : (
        <div className="gpt-empty"><span className="gpt-logo">✦</span><span>{t("Ask anything — or just say it.")}</span></div>
      )}
      <div className="gpt-inputbar">{inserted ? t("Structured prompt ready — press ⏎") : t("Message ChatGPT…")}</div>
    </div>
  );
}

const APP_SKIN = { notion: NotionDoc, cursor: CursorEditor, gmail: GmailCompose, chatgpt: ChatGPTInput };

function AppCanvas({ demo, phase }) {
  const t = window.SM.t;
  const c = window.SM.ctx[demo.ctx];
  const inserted = phase === "inserted";
  const Skin = APP_SKIN[demo.ctx] || NotionDoc;
  const fullBleed = demo.ctx === "cursor" || demo.ctx === "chatgpt";
  return (
    <div className="sc-window">
      <div className="sc-chrome">
        <span className="traffic"><i /><i /><i /></span>
        <span className="sc-tab"><span className="g" style={{ background: c.color }}>{c.glyph}</span>{c.name}</span>
        <span className="spacer" />
        <span className="meta">⌥Space · SpeakMind</span>
      </div>
      <div className="sc-app" style={fullBleed ? { padding: 0 } : undefined}>
        <div className={"sc-toast" + (inserted ? " show" : "")}><span className="d" />{t("Inserted into")} {c.name}</div>
        {fullBleed ? <Skin demo={demo} inserted={inserted} /> : <Skin demo={demo} inserted={inserted} />}
      </div>
    </div>
  );
}

/* ---- which Memory Dictionary terms this demo locks in ---- */
function dictTermsFor(demo) {
  const hay = JSON.stringify(demo.result) + " " + demo.raw;
  return window.SM.dict.filter((d) => hay.includes(d.term)).slice(0, 3);
}

/* ---- the real signal-strip waveform (ported from RecordingWaveform) ----
   7 bars, center-out, accent-hued. Listening: each bar pulses on its own
   timing (voice-reactive feel). Processing: dimmed + calmer. The shape
   [6,11,15,9,14,10,7] and per-bar durations mirror the macOS app. */
const WAVE_HEIGHTS = [6, 11, 15, 9, 14, 10, 7];
function SignalWave({ dimmed }) {
  return (
    <div className={"sig-wave" + (dimmed ? " dim" : "")} aria-hidden="true">
      {WAVE_HEIGHTS.map((h, i) => (
        <i key={i} style={{
          "--h": `${h * 1.7 + 6}px`,
          animationDuration: `${0.42 + (i % 4) * 0.06}s`,
          animationDelay: `${i * 0.025}s`,
        }} />
      ))}
    </div>
  );
}

/* The app shows one precise processing word, by mode — not a long sentence. */
const PROC_WORD = {
  Auto: "Cleaning up", Notes: "Structuring notes", Prompt: "Structuring prompt",
  Developer: "Refining", Write: "Composing", Translate: "Translating", Ask: "Answering",
};
const procWordFor = (demo) => PROC_WORD[demo.mode.name] || "Refining";

/* ---- compact floating overlay docked over the window ----
   idle + after-insert: folds into the resting Docklet (the app's signature
   signal strip). listening: the real signal strip — cancel · waveform · finish.
   processing: spinner + the precise per-mode word, then the live Context-Aware
   + Memory Dictionary footer (shown here for the demo; the app reveals it on
   the result card). All ported 1:1 from VoiceFlow's OverlayView. */
function FloatingOverlay({ demo, phase, words }) {
  const { Docklet } = window.SMDocklet;
  const t = window.SM.t;
  const c = window.SM.ctx[demo.ctx];
  const resting = phase === "idle" || phase === "inserted";
  const terms = dictTermsFor(demo);

  if (resting) {
    return (
      <div className="sc-dock sc-dock-rest">
        <Docklet auto lang={c.lang === "中文" ? "中" : "A"} />
        <div className="dk-rest-cap">{t("at rest · hover to expand")}</div>
      </div>
    );
  }

  return (
    <div className="sc-dock">
      <div className="sc-pill">
        <div className="sc-pill-top">
          <span className="ctx-chip">
            <span className="g" style={{ background: c.color }}>{c.glyph}</span>{c.name}
          </span>
          <span className={"ov-status" + (phase === "listening" ? " live" : "")}>
            <span className="led" />
            {phase === "listening" ? t("Listening") : t("Working")}
          </span>
        </div>

        {/* the real 96×24 signal strip, scaled up for the hero */}
        <div className="sc-strip">
          {phase === "listening" && <>
            <button className="sig-btn quiet" tabIndex={-1} aria-label="Cancel recording">✕</button>
            <SignalWave />
            <button className="sig-btn primary" tabIndex={-1} aria-label="Finish recording">⏎</button>
          </>}
          {phase === "processing" && <>
            <span className="sig-spin" aria-hidden="true" />
            <span className="proc-word">{t(procWordFor(demo))}</span>
          </>}
        </div>

        {phase === "listening" && <>
          <div className="transcript">{words.map((w, i) => <span key={i} className="w">{w}{" "}</span>)}<span className="caret" /></div>
          <div className="sc-listen-cap">{t("Listening… release to finish")}</div>
        </>}

        {phase === "processing" && (
          <div className="sc-meta">
            <div className="sc-meta-row">
              <span className="ic" style={{ background: c.color }}>{c.glyph}</span>
              <span><b>{t("Context Aware")}</b> {t("· adapted for")} {c.name} <span className="dim">— {t(c.hint)} · {c.lang}</span></span>
            </div>
            {terms.length > 0 && (
              <div className="sc-meta-row">
                <span className="ic dict">✦</span>
                <span className="sc-chips">
                  <span className="dim">{terms.length} {t("terms from your Memory Dictionary")}</span>
                  {terms.map((t) => <span key={t.term} className="sc-chip">{t.term}</span>)}
                </span>
              </div>
            )}
          </div>
        )}
      </div>
    </div>
  );
}

function HeroShowcase({ onChange }) {
  const { demo, phase, words, paused } = useDemoCycle(onChange);
  return (
    <div className="showcase"
      onMouseEnter={() => { paused.current = true; }}
      onMouseLeave={() => { paused.current = false; }}>
      <AppCanvas demo={demo} phase={phase} />
      <FloatingOverlay demo={demo} phase={phase} words={words} />
    </div>
  );
}

window.SMShowcase = { HeroShowcase, useDemoCycle };
