/* ============================================================
   act2.jsx — Act 2: the opportunity layer (high-fidelity rebuild)
   3 screens · chapter 机会 · accent var(--ch) ≈ #0e9f8e
   ============================================================ */
window.AP_SCREENS = window.AP_SCREENS || [];

/* ============================================================
   屏 1 · 范式转移（是重心转移，不是替换）
   ① 执行过程的「炫技秀」：推理核 + 环绕工具节点 + 流动连线，过程清晰可见、
      也很重要，但一直停在表演执行、迟迟不出结果（投资人在等）。
   ② 该出结果那一刻 —— 执行过程优雅地退到幕后（不是被摧毁，它依然在跑、
      依然可观测），把焦点让给结果：「范式没被推翻，重心从过程移到了结果。」
   ③ 新重心 = 干净笃定的竖向流水线：需求 → 智能路由分析调度 → 更好的交付结果。
   全程无任何产品 / logo。
   ============================================================ */
/* 流程图标 → Lucide 名（统一走 Icon 组件，不手画 SVG） */
const PROC_ICON = {
  think: "Clock", search: "Search", tool: "Wrench", branch: "Workflow",
  ask: "CircleHelp", doc: "FileText", chart: "ChartColumn",
};
function ProcGlyph({ ic }) {
  return <Icon className="pp-ic" name={PROC_ICON[ic] || PROC_ICON.think} stroke={1.8} />;
}
/* 智能路由「分析候选 Agent」的素材：路由是这屏主角，要展示它怎么评估、怎么选。
   注意是三个不同的「Agent」(不是大模型)；每个候选一个匹配分，pick=被选中的最优解。 */
const ROUTE_CANDIDATES = [
  { brand: "claudecode", name: "Claude Code · 编程型", note: "代码理解、多步执行",     score: 82 },
  { brand: "manus",      name: "Manus · 通用型",       note: "网页操作、任务交付", score: 95, pick: true },
  { brand: "rogo",     name: "Rogo · 分析型",     note: "结构化对比、出报告", score: 79 },
];
/* 执行过程 = 默默在后台跑的一行滚动状态（它在调工具/搜索/撰写，不是重点） */
const EXEC_ROLL = [
  "调用工具 · 抓取竞品官网与评测…",
  "调用工具 · 提取功能与定价…",
  "交叉核对 · 去重 / 校验…",
  "撰写中 · 差异化结论…",
];
/* 交付物 = 不止一个文件：成稿后由路由把结果送达到用户真实的工作流，
   顺手把归档 / 推送等「捎带的事」一并办完。brand 对应 lib.jsx 的 BrandTile。 */
const DELIVERS = [
  { brand: "feishu", to: "飞书",         act: "成稿 + 一句话摘要已发你", state: "已送达" },
  { brand: "notion", to: "Notion · 竞品库", act: "整篇归档，可检索复用",   state: "已归档" },
  { brand: "wechat", to: "微信",         act: "三条结论推到你手机",     state: "已推送" },
];
function ParadigmShift({ active, bus }) {
  const [phase, setPhase] = useState(0); // 0 需求+路由分析 · 1 路由收起+执行运行 · 2 执行完成+结果
  const scrub = useScrub({
    bus,
    autoplay: true,   // 到这屏即自动播放、依次出场，无需手动控制
    duration: 6000,
    reset: () => { setPhase(0); bus.setReady(false); bus.setHint(null); },
    /* 自动播放·依次出场（上一段动画完成再出下一段）：
       ① 收到需求 → 智能路由「展开」分析候选 Agent、选中最匹配(重头动画)
       ② 路由收起为「已选中」→ 执行过程出现并运行(一行滚动)
       ③ 执行「完成」→ 完整结果落定。 */
    frames: [
      { t: 2400, apply: () => setPhase(1) },
      { t: 4200, apply: () => setPhase(2) },
      { t: 5200, apply: () => { bus.setReady(true); bus.setHint(null); } },
    ],
  });

  const stage = "pd-stage2 ph-" + phase;
  return (
    <div className="paradigm">
      <Scrubber ctl={scrub} label="范式转移" />
      <div className="pd-head fade-up">
        <h2 className="h-title">范式的重心：从看过程，到要结果</h2>
      </div>

      <div className={stage}>
        {/* 自动播放的流水线：收到需求 → 智能路由(展开分析→收起选中·主角) → 执行(默默滚动) → 完整结果 */}
        <div className="pd-panel">
          <div className="pp-flow">
            {/* ① 收到需求 */}
            <div className="ppf-step s-req">
              <span className="ppf-cap">收到需求</span>
              <span className="ppf-req">帮我把这 3 家竞品摸透，出一份差异化策略</span>
            </div>
            <span className="ppf-link l1" />
            {/* ② 智能路由 —— 主角：phase 0「展开」分析候选 Agent；phase 1 起「收起」为已选中 */}
            <div className="ppf-step s-route">
              {/* 展开态：正在分析、给候选打分、选中最匹配 */}
              <div className="rt-analyze">
                <div className="rt-head">
                  <span className="ppl-spin" />
                  <span className="rt-head-t">智能路由 · 正在分析任务，匹配最合适的 Agent</span>
                </div>
                <div className="rt-cands">
                  {ROUTE_CANDIDATES.map((c, i) => (
                    <div key={i} className={"rt-cand" + (c.pick ? " pick" : "")} style={{ "--ci": i }}>
                      <BrandTile brand={c.brand} size={26} radius={7} soft={false} />
                      <div className="rt-cand-meta">
                        <span className="rt-cand-name">{c.name}</span>
                        <span className="rt-cand-note">{c.note}</span>
                      </div>
                      <span className="rt-cand-bar"><i style={{ "--w": c.score + "%" }} /></span>
                      <span className="rt-cand-pct">{c.score}</span>
                      <span className="rt-cand-pick">选中</span>
                    </div>
                  ))}
                </div>
              </div>
              {/* 收起态：已选中最匹配的 Agent（保留「重」的视觉权重） */}
              <div className="ppf-route rt-collapsed">
                <span className="ppf-route-ic"><ProcGlyph ic="branch" /></span>
                <span className="ppf-route-t">智能路由 · 已选中最匹配的 Agent</span>
                <span className="ppf-route-tags"><i>快</i><i>省</i><i>可信</i></span>
              </div>
            </div>
            <span className="ppf-link l2" />
            {/* ③ 执行过程 —— 运行(一行滚动) → 完成(✓)。运行中用 spinner 表示，非小圆点 */}
            <div className="ppf-step s-exec">
              <span className="ex-ind">
                <span className="ex-spin" />
                <span className="ex-check"><DoneTick size={18} /></span>
              </span>
              <span className="ex-label ex-label-run">执行中</span>
              <span className="ex-label ex-label-ok">执行完成</span>
              <span className="ex-roll">
                <span className="ex-roll-track">
                  {EXEC_ROLL.map((t, i) => <span key={i} className="ex-roll-line">{t}</span>)}
                  <span className="ex-roll-line">{EXEC_ROLL[0]}</span>
                </span>
              </span>
              <span className="ex-done-meta">4 步 · 1m24s</span>
            </div>
            <span className="ppf-link l3" />
            {/* ④ 完整结果 —— 主角卡 */}
            <div className="ppf-step s-deliver">
              <div className="dv-card">
                <div className="dv-head">
                  <span className="dv-ic"><ProcGlyph ic="doc" /></span>
                  <div className="dv-tt">
                    <div className="dv-title">竞品差异化策略 · 已成稿</div>
                    <div className="dv-sub">PDF 12 页 · 8 处来源核对</div>
                  </div>
                  <span className="dv-badge">符合预期</span>
                </div>
                <div className="dv-drops">
                  {DELIVERS.map((d, i) => (
                    <div key={i} className="dv-drop">
                      <BrandTile brand={d.brand} size={28} radius={8} soft={false} />
                      <div className="dv-drop-tt">
                        <span className="dv-drop-to">{d.to}</span>
                        <span className="dv-drop-act">{d.act}</span>
                      </div>
                      <span className="dv-drop-state"><DoneTick size={14} />{d.state}</span>
                    </div>
                  ))}
                </div>
                <div className="dv-verdict"><b>一次办完</b> 你只说了一句话 —— 调研、成稿到送达、归档，结果直接落到你手上，不是甩你一个文件</div>
              </div>
            </div>
          </div>
        </div>
      </div>

      {/* 动画结束后(phase 2)淡入的一句话场景描述；其下由 shell 显示「轻点屏幕任意处继续」 */}
      <div className="pd-foot">
        <p className={"pd-claim" + (phase >= 2 ? " fade-up" : "")} style={{ visibility: phase >= 2 ? "visible" : "hidden" }}>
          你只说一句话，剩下的交给路由 —— <b>重心，从过程迁移到了结果。</b>
        </p>
      </div>
    </div>
  );
}

/* ============================================================
   屏 2 · 为什么是现在 —— 编辑式「盘点」：四件观察被逐条点亮，
   一条脊线累积下来；前三件是已就位的使能条件，第四件是至今
   没人填的空白（留给我们的入口）。严格对应故事《我们看到了什么》。
   ============================================================ */
const WHY_GLYPH = {
  power: "Zap",            // 闪电 · 能力
  cost: "TrendingDown",    // 下行 · 成本
  supply: "Layers",        // 堆叠 · 供给
  standard: "Award",       // 奖章 · 标准
};
function WhyGlyph({ ic }) {
  return <Icon name={WHY_GLYPH[ic]} stroke={1.9} />;
}
/* 图像化盘点：四块极简磁贴。前三块是已就位的使能条件，第四块是没人填的空白。
   严格对应故事《我们看到了什么》一/二/三/四，文字压到一句以内。 */
const WHY = [
  { n: "01", ic: "power",    head: "已经有人在用", cap: "顶级 agent 是刚需，却难用又封闭",  brands: ["claudecode", "codex", "hermes", "openclaw"], flag: "强需求",
    pain: "开源的 OpenClaw / Hermes 用户已经很多，但门槛太高、配置极复杂；Codex / Claude Code 更易上手、用户更广，却只能在自家 App 里远端调用本机、生态封闭只能用自家模型，订阅还很贵",
    fix: "把最好的开源整合进来，门槛拉到最低 —— 普通人开口就能用；再用智能路由把成本压下来" },
  { n: "02", ic: "cost",     head: "又便宜又能打", cap: "国产模型逼近顶级", brands: ["deepseek", "qwen", "kimi"],    flag: "已成立",
    pain: "可没人替你决定 —— 哪个任务该交给哪个模型才又省又好",
    fix: "智能路由按难度 / 成本自动选路：简单的给国产，难的给顶级" },
  { n: "03", ic: "supply",   head: "Token 在闲置", cap: "付过钱却没出口",   brands: ["cpu", "server"],               flag: "待释放",
    pain: "订阅用不完、API key 闲着、本地模型平时空转",
    fix: "把闲置 Token 接成网络安全接单，闲着的额度反过来替你赚钱" },
  { n: "04", ic: "standard", head: "没人能评好坏", cap: "谁做得最好？",     brands: ["chart"],                        flag: "还空着", gap: true,
    pain: "至今没有高质量的 benchmark 能评 agent 到底做得好不好",
    fix: "路由攒下真实交付的满意度数据 —— 哪类任务交给谁结果最好，按结果反推评测，没人在做" },
];
function WhyTile({ w, i, extra }) {
  return (
    <div className={"wtile" + (w.gap ? " gap" : "") + (extra || "")} style={{ "--d": 0.1 + i * 0.16 + "s" }}>
      <span className="wtile-num">{w.n}</span>
      <span className="wtile-ic"><WhyGlyph ic={w.ic} /></span>
      <div className="wtile-head">{w.head}</div>
      <div className="wtile-cap">{w.cap}</div>
      <div className="wtile-brands">
        {w.brands.map((b) => <BrandTile key={b} brand={b} size={22} radius={6} soft={false} />)}
      </div>
      <span className="wtile-pill">{w.flag}</span>
      {w.gap && <span className="wtile-gaptag">留给我们</span>}
    </div>
  );
}
/* 枢纽板：总览态 / 单点聚焦态 共用同一组 DOM 节点 —— 这正是「就地高亮」的关键，
   从 mode=overview 切到 mode=focus 时磁贴是同一批节点，只切 class，由 CSS 把高亮 /
   压暗补间出来；标题、副标题用 key 触发重渲，文案带动画替换。f 收集动画开关。 */
function WhyBoard({ mode, idx, f }) {
  const focus = mode === "focus";
  const w = focus ? WHY[idx] : null;
  return (
    <>
      <div className="wn-head">
        <h2 className="h-title wn-morph" key={focus ? "t" + idx : "tov"}>{focus ? w.head : "为什么是现在"}</h2>
        <p className="wn-sub wn-morph" key={focus ? "s" + idx : "sov"}>{focus ? w.cap : "四件一直分开看的事，正好同时成立。"}</p>
      </div>

      <div className={"wn-tiles"
        + (f.counted ? " counted" : "")
        + (!focus && f.concluded ? " concluded" : "")
        + (f.focusing ? " focusing" : "")}>
        {WHY.map((x, i) => (
          <WhyTile key={i} w={x} i={i} extra={focus ? (i === idx ? " is-focus" : " is-dim") : ""} />
        ))}
      </div>

      <div className="wn-foot">
        {!focus && (
          <p className={"wn-line" + (f.concluded ? " fade-up" : "")} style={{ visibility: f.concluded ? "visible" : "hidden" }}>
            三块已经就位，第四块还空着 —— <b>接到一起，答案已经很清楚。</b>
          </p>
        )}
      </div>
    </>
  );
}
/* 枢纽屏：四拍 —— ①盘点四件 ②结论 ③就地高亮第一件(文案带动画替换) → 之后翻到深讲屏。
   方向键逐拍推进，点击则自动播完整屏。第③拍 mode overview→focus 是同一组磁贴就地变化。
   focus prop 用于点 2/3/4 从深讲屏回来时的独立高亮屏。 */
function WhyNow({ active, bus, focus }) {
  if (focus) return <WhyFocus active={active} bus={bus} idx={focus - 1} />;
  const [counted, setCounted] = useState(false);
  const [concluded, setConcluded] = useState(false);
  const [mode, setMode] = useState("overview");
  const [focusing, setFocusing] = useState(false);
  const [bridged, setBridged] = useState(false);
  const tl = useTimeline();

  const scrub = useScrub({
    bus,
    duration: 3500,
    autoStart: true,   // 进屏即呈现到「结论」停顿点（四件就位），再按一拍才就地高亮第一件
    reset: () => {
      tl.clear();
      setCounted(false); setConcluded(false);
      setMode("overview"); setFocusing(false); setBridged(false);
      bus.setReady(false); bus.setHint(null);
    },
    /* 两段：① 盘点四件 + 结论（一按全呈现）② 就地高亮第一件、文案带动画替换。 */
    frames: [
      { t: 550,  label: "盘点", apply: () => setCounted(true) },
      { t: 1700, label: "结论", stop: true, apply: () => { setConcluded(true); bus.setHint("第四块还空着 —— 我们一件件看怎么落地"); } },
      { t: 2800, label: "聚焦①", apply: () => {
          setConcluded(false); setMode("focus"); bus.setReady(false); bus.setHint(null);
          tl.at(40,  () => setFocusing(true));
          tl.at(440, () => setBridged(true));
          tl.at(720, () => { bus.setReady(true); bus.setHint(null); });
        } },
    ],
  });

  return (
    <div className="whynow">
      <Scrubber ctl={scrub} label="为什么是现在" />
      <WhyBoard mode={mode} idx={0} f={{ counted, concluded, focusing, bridged }} />
    </div>
  );
}
/* 点 2/3/4：从深讲屏回到枢纽，独立高亮屏。两拍 —— ①高亮当前件 ②浮出解法。
   磁贴一进场即可见（counted 常驻），不重放整屏盘点。 */
function WhyFocus({ active, bus, idx }) {
  const [focusing, setFocusing] = useState(false);
  const [bridged, setBridged] = useState(false);
  const scrub = useScrub({
    bus,
    duration: 1300,
    reset: () => { setFocusing(false); setBridged(false); bus.setReady(false); bus.setHint(null); },
    frames: [
      { t: 200, label: "高亮", apply: () => setFocusing(true) },
      { t: 800, label: "解法", apply: () => { setBridged(true); bus.setReady(true); bus.setHint(null); } },
    ],
  });
  /* 分点屏(点2/3/4)：正向进屏即自动交错揭示「高亮当前件 → 浮出文案」，无需再手动点一下。
     用 setTimeout（非 rAF）驱动 —— 标签切到后台也能触发，且首帧为未高亮态，后续切类由 CSS 过渡动画呈现；
     经 scrub.seek 应用关键帧并把 appliedRef 推到末帧，方向键右仍直接翻下一屏。
     （点1 是枢纽屏 WhyNow 的总览→就地替换，保持手动；返回方向由 useScrub 直接呈现末态。） */
  useEffect(() => {
    if (bus.entryDir === "back") return;
    const a = setTimeout(() => scrub.seek(200), 60);    // 高亮当前件
    const b = setTimeout(() => scrub.seek(1300), 480);  // 浮出痛点→解法 + 就绪提示
    return () => { clearTimeout(a); clearTimeout(b); };
  }, []);
  return (
    <div className="whynow whynow-focus">
      <Scrubber ctl={scrub} label={"为什么是现在 · " + WHY[idx].n} />
      <WhyBoard mode="focus" idx={idx} f={{ counted: true, concluded: false, focusing, bridged }} />
    </div>
  );
}

/* ============================================================
   屏 3 · 市场有多大，我们能切多大
   ============================================================ */
const BARS = [
  { k: "Coding Agent", v: 26.0, year: "2030", entry: true, note: "切入点 · 可客观验收", cagr: "27%" },
  { k: "通用 Agent", v: 50.3, year: "2030", note: "扩展 · 通用任务交付", cagr: "46%" },
  { k: "平台底座", v: 179.0, year: "2030", note: "闲置 Token 撮合 · API 流量", cagr: "32%" },
];
function useTicker(target, run, ms = 1000) {
  const [val, setVal] = useState(0);
  useEffect(() => {
    if (!run) { setVal(0); return; }
    let raf, start;
    const step = (ts) => {
      if (!start) start = ts;
      const p = Math.min(1, (ts - start) / ms);
      const eased = 1 - Math.pow(1 - p, 3);
      setVal(target * eased);
      if (p < 1) raf = requestAnimationFrame(step);
    };
    raf = requestAnimationFrame(step);
    return () => cancelAnimationFrame(raf);
  }, [run, target]);
  return val;
}
function BarCol({ b, i, grown, hover, setHover, max }) {
  const tv = useTicker(b.v, grown, 1100);
  return (
    <div className={"bar-col" + (b.entry ? " entry" : "") + (hover === i ? " hov" : "")}
      onMouseEnter={() => setHover(i)} onMouseLeave={() => setHover(null)}>
      <div className="bar-val" style={{ opacity: grown ? 1 : 0 }}>
        <span className="bar-cur">$</span>{tv.toFixed(1)}<span className="bar-unit">B</span>
      </div>
      <div className="bar-track">
        {b.entry && grown && (
          <span className="bar-entry-tag" style={{ bottom: (b.v / max) * 100 + "%" }}>
            <span className="bar-entry-badge">切入点</span>
          </span>
        )}
        <div className="bar-fill" style={{ height: grown ? (b.v / max) * 100 + "%" : "0%", transitionDelay: 0.2 + i * 0.16 + "s" }}>
          <span className="bar-shine" />
        </div>
      </div>
      <div className="bar-k">{b.k}</div>
      <div className="bar-note">{b.note}</div>
      <div className="bar-year">{b.year} · 年增 {b.cagr}</div>
    </div>
  );
}
function MarketSize({ active, bus }) {
  const [grown, setGrown] = useState(false);
  const [hover, setHover] = useState(null);
  const max = 200;
  const scrub = useScrub({
    bus,
    autoplay: true,   // 进屏即自动播放柱子动画（点击/方向键进入都不再需要多按一次）
    duration: 2900,
    reset: () => { setGrown(false); bus.setReady(false); bus.setHint("悬停柱子看具体数字"); },
    frames: [
      { t: 800, label: "增长", apply: () => setGrown(true) },
      { t: 2400, label: "完成", apply: () => { bus.setReady(true); bus.setHint("先切最可验收的任务，站稳再扩展"); } },
    ],
  });
  return (
    <div className="market">
      <Scrubber ctl={scrub} label="市场规模" />
      <div className="mk-head fade-up">
        <h2 className="h-title">市场有多大，我们能切多大</h2>
        <p className="mk-sub">从最可验收的 Coding Agent 切入，外溢到通用 Agent，最终用智能路由把用户<b>闲置的 Token</b>调度起来，成为平台底座。</p>
      </div>

      <div className="mk-chart">
        <div className="mk-grid">
          {[0, 1, 2, 3].map((g) => <span key={g} className="mk-gridline" style={{ bottom: g * 25 + "%" }} />)}
        </div>
        <div className="mk-bars">
          {BARS.map((b, i) => (
            <BarCol key={i} b={b} i={i} grown={grown} hover={hover} setHover={setHover} max={max} />
          ))}
        </div>
      </div>

      <div className="mk-foot">
        <p className={"mk-line" + (grown ? " fade-up" : "")} style={{ visibility: grown ? "visible" : "hidden" }}>
          先切最可验收的 Coding Agent —「<b>快、省、可信</b>」是硬指标，能立刻证明；再扩展到通用 Agent。Token 用量爆发、单价却年降 60%+，大量订阅额度被白白浪费 —— 我们用<b>智能路由把这些闲置 Token 撮合起来</b>，让平台直接长在最大的那笔流量上。
        </p>
      </div>
    </div>
  );
}

/* 二幕只放到「为什么是现在」枢纽屏为止；四点的逐个高亮 + 深讲 + 市场，
   由 act3.jsx 统一穿插编排（见其末尾 push）。MarketSize / WhyNow 为全局可复用。 */
window.AP_SCREENS.push(
  { id: "act2-paradigm", chapter: "机会", Comp: ParadigmShift },
  { id: "act2-whynow", chapter: "机会", Comp: WhyNow },
);
