import { Fragment, useState } from "react";
import type { CSSProperties } from "react";
import { Play } from "lucide-react";
import type { BillingSummary, Product, Project, Team, User } from "../types";
import type { Notice, Page } from "./route-config";
import { money, stageOrder, statusPill } from "./stage-config";
import { CornerMarks, Decorations, Sidebar, ToastLike } from "../components/app-shell";
import { IconKitSvg } from "../components/IconKitSvg";

// 镜像 shell.js→mock-media.js 给 .placeholder 注入 mock 图;React 手动复刻对应映射
const mock = (file: string): CSSProperties => ({ ["--mock-media-url"]: `url(/exact/assets/mock/${file})` } as CSSProperties);

// Stage 3 故事板 · 镜像 JS 注入的 3 场(全 mock)
const SB_SCENES = [
  { sid: "sc1", nm: "场 1", sub: "0-15s", frame: "深夜办公桌", img: "scene-office.png" },
  { sid: "sc2", nm: "场 2", sub: "15-30s", frame: "面膜包装/特写", img: "product-mask.png" },
  { sid: "sc3", nm: "场 3", sub: "30-45s", frame: "化妆台/产品定格", img: "cover-mask-final.png" }
];
const SB_PROMPT = "中景 / 固定机位\n光线:台灯暖光 + 屏幕冷光\n演员:林夕(疲倦状态)\n关键道具:面膜盒(从抽屉露半角)\n氛围:午夜、安静、些许焦虑";

// Stage 4 视频 · 镜像 3 场(全 mock,video-thumb 经 mock-media 映射封面图)
const VIDEO_CARDS = [
  { vid: "v1", frame: "场 1 · 0-15s", title: "场 1 · 深夜办公桌", meta: "15s · 1080×1920 · ¥0.45", img: "cover-mask-v3.png" },
  { vid: "v2", frame: "场 2 · 15-27s", title: "场 2 · 面膜包装/特写", meta: "12s · 1080×1920 · ¥0.45", img: "product-mask.png" },
  { vid: "v3", frame: "场 3 · 27-40s", title: "场 3 · 化妆台/产品定格", meta: "13s · 1080×1920 · ¥0.45", img: "cover-mask-final.png" }
];

// Stage 5 拼接编辑器 · 全 mock(镜像时间轴引擎按 data-dur 累计定位,React 直接算 left/width)
const ED_VIDEO_CLIPS = [
  { n: 1, lbl: "深夜办公桌", dur: 2 }, { n: 2, lbl: "面膜包装", dur: 3 }, { n: 3, lbl: "精华液微距", dur: 3 },
  { n: 4, lbl: "敷面膜平躺", dur: 3 }, { n: 5, lbl: "化妆台", dur: 2 }, { n: 6, lbl: "产品定格", dur: 2 }
];
const ED_SUB_CLIPS = [
  { lbl: "加班三天 脸已经不能看了…", dur: 2 }, { lbl: "还好我有这个 透真玻尿酸面膜", dur: 3 }, { lbl: "30g 精华 一片顶三片", dur: 3 },
  { lbl: "敷完起来脸是软的", dur: 3 }, { lbl: "化妆都能看出来", dur: 2 }, { lbl: "5 片 ¥39.9 囤起来", dur: 2 }
];
const ED_RULER: Array<{ left: string; major: boolean; t?: string }> = [
  { left: "0%", major: true, t: "0s" }, { left: "6.67%", major: false }, { left: "13.33%", major: true, t: "2s" }, { left: "20%", major: false },
  { left: "26.67%", major: true, t: "4s" }, { left: "33.33%", major: false }, { left: "40%", major: true, t: "6s" }, { left: "46.67%", major: false },
  { left: "53.33%", major: true, t: "8s" }, { left: "60%", major: false }, { left: "66.67%", major: true, t: "10s" }, { left: "73.33%", major: false },
  { left: "80%", major: true, t: "12s" }, { left: "86.67%", major: false }, { left: "93.33%", major: true, t: "14s" }, { left: "100%", major: true, t: "15s" }
];
const ED_WAVE: Array<[number, number]> = [[8,4],[6,8],[3,14],[7,6],[4,12],[2,16],[6,8],[8,4],[5,10],[3,14],[7,6],[4,12],[6,8],[2,16],[5,10],[7,6],[3,14],[6,8],[8,4],[4,12],[2,16],[5,10],[7,6],[3,14],[6,8],[4,12],[8,4],[5,10],[2,16],[7,6],[3,14],[6,8],[4,12],[8,4],[5,10],[3,14],[6,8],[2,16],[7,6],[4,12],[5,10],[3,14],[6,8],[8,4],[4,12],[2,16],[5,10],[7,6],[3,14],[6,8],[8,4],[4,12],[2,16],[6,8],[5,10],[3,14],[7,6],[4,12],[8,4],[6,8],[2,16],[5,10],[3,14],[7,6],[6,8],[4,12],[8,4],[5,10],[2,16],[7,6],[3,14],[6,8],[4,12],[8,4],[5,10],[3,14],[6,8],[2,16],[7,6],[4,12],[5,10],[3,14],[6,8],[8,4],[4,12],[2,16],[5,10],[7,6],[3,14],[6,8],[8,4],[4,12],[2,16],[6,8],[5,10],[3,14],[7,6],[4,12],[8,4],[6,8],[2,16],[5,10],[3,14],[7,6],[6,8],[4,12],[8,4],[5,10],[2,16],[7,6],[3,14],[6,8],[4,12],[8,4],[5,10],[3,14],[6,8],[2,16],[7,6],[4,12],[5,10],[3,14],[6,8],[8,4],[4,12],[2,16],[5,10],[7,6],[3,14],[6,8],[8,4],[4,12],[2,16],[6,8],[5,10],[3,14],[7,6],[4,12],[8,4],[6,8],[2,16],[5,10],[3,14],[7,6],[6,8],[4,12],[8,4],[5,10],[3,14],[6,8]];
function edLayout<T extends { dur: number }>(clips: T[]): Array<T & { leftPct: number; widthPct: number }> {
  let acc = 0;
  return clips.map((c) => { const left = acc; acc += c.dur; return { ...c, leftPct: (left / 15) * 100, widthPct: (c.dur / 15) * 100 }; });
}

const STAGE_STEPS: Array<{ n: number; label: string }> = [
  { n: 1, label: "脚本" },
  { n: 2, label: "基础资产" },
  { n: 3, label: "故事板" },
  { n: 4, label: "视频" },
  { n: 5, label: "拼接导出" }
];

export function PipelinePage(props: {
  project: Project;
  loading: boolean;
  navigate: (page: Page, options?: { projectId?: string; productId?: string }) => void;
  user: User;
  team: Team;
  products: Product[];
  projects: Project[];
  billing: BillingSummary | null;
  notice: Notice | null;
  avatarChar: string;
  logout: () => void;
  onRefresh: () => void;
  onGenerateScript: (prompt: string) => void;
  onAdoptScript: (scriptId: string) => void;
  onGenerateBaseAsset: (kind: "product" | "person" | "scene", prompt: string) => void;
  onGenerateStoryboard: (prompt: string) => void;
  onSkipStoryboard: () => void;
  onSubmitVideo: (segmentId: string, prompt: string) => void;
  onPollVideo: (segmentId: string) => void;
  onSubmitAllVideos: (prompt: string) => void;
  onPollAllVideos: () => void;
  onSubmitExport: () => void;
}) {
  const {
    project, loading, navigate, user, team, products, projects, billing, notice, avatarChar, logout,
    onGenerateScript, onGenerateBaseAsset, onGenerateStoryboard, onSkipStoryboard,
    onSubmitVideo, onPollVideo, onSubmitAllVideos, onPollAllVideos, onSubmitExport
  } = props;

  // 步进器:对齐镜像 activateStage 逻辑。默认(无 hash)pane=脚本(1) 但步进器 active=项目真实阶段;
  // 一旦导航(hash 或点击),active 跟随所看阶段,completed=max(项目阶段-1, 所看阶段-1)。
  const projectStage = project.status === "completed" ? 5 : Math.max(1, (stageOrder as readonly string[]).indexOf(project.current_stage) + 1);
  const initHash = typeof location !== "undefined" ? location.hash.match(/#stage-(\d)/) : null;
  const [viewStage, setViewStage] = useState(initHash ? Number(initHash[1]) : 1);
  const [navigated, setNavigated] = useState(Boolean(initHash));
  const activeDot = navigated ? viewStage : projectStage;
  const completed = Math.max(projectStage - 1, activeDot - 1);
  const [chatText, setChatText] = useState("");
  const [storyboardPrompt, setStoryboardPrompt] = useState("统一商品、人物、场景风格,生成可直接指导视频的分镜图");
  const [videoPrompt, setVideoPrompt] = useState("竖屏电商短视频,镜头稳定,商品露出清晰,节奏有转化感");
  const canExport = project.video_segments.length > 0 && project.video_segments.every((segment) => Boolean(segment.adopted_version));
  // 真实商品名(api-bridge 仅 hydrate 商品名,其余人物/场景沿用设计稿 mock)
  const productName = products.find((item) => item.id === project.product)?.title || "透真补水面膜";

  function goStage(n: number) {
    setViewStage(n);
    setNavigated(true);
    if (typeof location !== "undefined") location.hash = `stage-${n}`;
  }
  function dotCls(n: number) {
    if (n === activeDot) return "sp-dot active";
    if (n <= completed) return "sp-dot done";
    return "sp-dot";
  }

  return (
    <div className="app pipeline-page">
      <Sidebar page="pipeline" navigate={navigate} user={user} team={team} products={products} projects={projects} />
      <main>
        <Decorations />
        <header className="topbar">
          <div className="pipeline-topbar-left">
            <a className="btn btn-ghost pipeline-back" href="/projects" onClick={(event) => { event.preventDefault(); navigate("projects"); }} aria-label="返回视频项目">
              <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><path d="M19 12H5" /><path d="M12 19l-7-7 7-7" /></svg>
              返回视频项目
            </a>
            <div className="pipeline-topbar-title" title={project.name}>
              {project.name}<span className="mono">// PIPELINE</span>
            </div>
          </div>
          <div className="right">
            <span className="balance-chip" onClick={() => navigate("account")}>
              <IconKitSvg name="creditCard" />
              余额 <strong>{money(billing?.account.balance)}</strong>
            </span>
            <button className="icon-btn" type="button" onClick={() => navigate("messages")} title="消息中心">
              <IconKitSvg name="bell" />
              <span className="count-noti">12</span>
            </button>
            <div className="topbar-avatar" onDoubleClick={logout} title="账户(双击退出)">
              <span>{avatarChar}</span>
            </div>
          </div>
          <div className="stage-pill" id="stage-pill">
            {STAGE_STEPS.map((step, index) => (
              <Fragment key={step.n}>
                <a className={dotCls(step.n)} data-stage={step.n} href={`#stage-${step.n}`} onClick={(event) => { event.preventDefault(); goStage(step.n); }}>
                  <span className="d"></span><span className="l">{step.label}</span>
                </a>
                {index < STAGE_STEPS.length - 1 && <span className={`sp-line${step.n <= completed ? " done" : ""}`}></span>}
              </Fragment>
            ))}
          </div>
        </header>

        <div className="content content--fh content--fh-flat" id="page-content">
          <CornerMarks />
          {notice && <ToastLike notice={notice} />}

          {/* ============= STAGE 1 · 脚本 ============= */}
          <section className={`stage${viewStage === 1 ? " active" : ""}`} data-stage-pane="1">
            <div className="stage-script">
              <div className="pane shot-list">
                <div className="pane-h">
                  <div className="shot-headline">
                    <strong>镜头脚本</strong>
                    <span className="muted-2 mono" id="shots-meta" style={{ fontSize: "11px" }}>· 空 · 待生成</span>
                  </div>
                  <div className="script-brief-summary" aria-label="当前创作方向">
                    <span className="pill neutral script-brief-pill"><span className="k">来源</span><span className="v" id="brief-source">未选择</span></span>
                    <span className="pill neutral script-brief-pill"><span className="k">风格</span><span className="v" id="brief-style">待确认</span></span>
                    <span className="pill neutral script-brief-pill"><span className="k">人物</span><span className="v" id="brief-persona">待确认</span></span>
                  </div>
                  <div className="script-tags" id="script-tags">
                    <div className="tag-group" data-kind="char">
                      <span className="tg-lbl">// 人物</span>
                      <button className="tag-add" type="button" aria-label="添加人物">+</button>
                    </div>
                    <div className="tag-group" data-kind="scene">
                      <span className="tg-lbl">// 场景</span>
                      <button className="tag-add" type="button" aria-label="添加场景">+</button>
                    </div>
                  </div>
                  <span className="spacer"></span>
                  <button className="btn btn-ghost btn-sm" type="button" id="chat-regen-btn">↻ 整体重写</button>
                </div>
                <div className="shots-body" id="shots-body">
                  <div className="shots-empty">
                    <div className="empty-ico"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="5" width="18" height="14" rx="2" /><path d="M3 10h18M9 5v14" /></svg></div>
                    <div className="empty-title">还没有镜头脚本</div>
                    <div className="empty-hint">// 跟右侧脚本助手对话<br />选择一种方式生成你的第一稿</div>
                  </div>
                </div>
              </div>

              <div className="stage-script-gutter" id="stage-script-gutter" role="separator" aria-orientation="vertical" aria-label="拖动调整脚本助手宽度"></div>

              <div className="pane chat-pane">
                <div className="pane-h">
                  <div className="ai-avatar">AI</div>
                  <strong>脚本助手</strong>
                  <span className="muted-2 mono" style={{ fontSize: "11px" }}>· GPT-4o</span>
                  <span className="spacer"></span>
                  <button className="btn btn-ghost btn-sm" type="button" id="chat-clear-btn">清空对话</button>
                </div>
                <div className="chat-body" id="chat-body">
                  <div className="chat-empty">
                    <div className="ce-title">选择一种生成方式开始</div>
                    <div className="ce-hint">// 三种,由「最省事」到「最保真原意」</div>
                    <div className="chat-modes">
                      <button className="chat-mode primary" type="button" data-mode="ai" disabled={loading} onClick={() => onGenerateScript("AI 全生 · 突出商品卖点,节奏紧凑,适合短视频投放")}><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M12 3l1.7 4.6L18 9l-4.3 1.4L12 15l-1.7-4.6L6 9l4.3-1.4L12 3z" /></svg>AI 全生</button>
                      <button className="chat-mode" type="button" data-mode="theme"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M9 18h6" /><path d="M10 22h4" /><path d="M15 14a4.65 4.65 0 0 0 1.4-2.5A6 6 0 1 0 6 8c0 1 .23 2.23 1.5 3.5" /></svg>一句话主题</button>
                      <button className="chat-mode" type="button" data-mode="manual"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" /><path d="M14 2v6h6" /></svg>自带脚本</button>
                    </div>
                  </div>
                </div>
                <div className="chat-input">
                  <div className="chat-input-card">
                    <div className="chat-attach-row" id="chat-attach-row" hidden></div>
                    <textarea className="chat-input-area" id="chat-textarea" placeholder="直接说怎么改,如:更像小红书种草 / 换成熬夜党" rows={2} value={chatText} onChange={(event) => setChatText(event.target.value)}></textarea>
                    <div className="chat-input-foot">
                      <button className="chat-icon-btn" id="chat-upload-btn" type="button" title="上传脚本附件" aria-label="上传脚本附件">
                        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M12 5v14M5 12h14" /></svg>
                      </button>
                      <span className="spacer"></span>
                      <button className="chat-send-btn" id="chat-send-btn" type="button" title="发送" aria-label="发送" disabled={loading || !chatText.trim()} onClick={() => { onGenerateScript(chatText.trim()); setChatText(""); }}>
                        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M13 6l6 6-6 6" /></svg>
                      </button>
                    </div>
                  </div>
                </div>
              </div>
            </div>

            <div className="stage-foot">
              <div className="info"><span className="mono">[ LLM 用量 ~2.4k tokens · ¥0.04 · 失败不扣 · 通过后扣 ]</span></div>
              <div className="hstack">
                <button className="btn" type="button" disabled={loading} onClick={() => onGenerateScript("整体重新生成 · 突出商品卖点,节奏紧凑")}><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M4 12a8 8 0 0 1 14-5.5L21 9" /><path d="M21 4v5h-5" /><path d="M20 12a8 8 0 0 1-14 5.5L3 15" /><path d="M3 20v-5h5" /></svg> 重新生成全部</button>
                <button className="btn btn-primary btn-lg" type="button" onClick={() => goStage(2)}>确认脚本,进入下一步 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M12 5l7 7-7 7" /></svg></button>
              </div>
            </div>
          </section>

          {/* Stage 2-5 · 暂沿用既有功能性结构(默认隐藏),后续逐阶段做像素还原 */}
          {viewStage === 2 && (
            <section className="stage active" data-stage-pane="2">
              <div className="stage-assets">
                <div className="asset-side">
                  <div className="ttab active" data-jump="asset-sec-products"><span>商品</span><span className="num">3 张</span></div>
                  <div className="ttab" data-jump="asset-sec-characters"><span>人物</span><span className="num">2/2</span></div>
                  <div className="ttab" data-jump="asset-sec-scenes"><span>场景</span><span className="num">3/3</span></div>
                  <div className="info">
                    基础资产是后续故事板的素材。所有卡片同时展示,点左侧分类直接定位。
                    <br /><br />
                    <strong className="mono">// 人物 +¥0.20/张</strong>
                    <strong className="mono">// 场景 +¥0.15/张</strong>
                    <span style={{ color: "var(--black-alpha-48)" }}>商品图无成本(直接复用商品库)</span>
                  </div>
                </div>

                <div className="asset-main">
                  <section className="asset-sec" id="asset-sec-products">
                    <div className="sec-h"><h3>商品 · <span id="asset-prod-name">{productName}</span></h3><span className="spacer"></span></div>
                    <div className="prod-row">
                      <div className="asset-card-2 prod-lib-card" data-asset-kind="product" data-asset-id="prod-main" id="asset-prod-card">
                        <div className="placeholder prod-thumb has-mock-media" style={mock("product-mask.png")}>
                          <span className="tri-missing-badge" id="asset-prod-tri-badge" tabIndex={0} role="button" aria-label="缺三视图,查看说明">
                            <span className="ico" aria-hidden="true"></span>
                            <span className="lbl-mono">缺三视图</span>
                            <span className="tri-missing-pop" role="tooltip">
                              <span className="pop-h">
                                <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M12 9v4M12 17h.01" /><path d="M10.3 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" /></svg>
                                MISSING TRI-VIEW
                              </span>
                              <span className="pop-body">该商品还未生成 <b>正 / 侧 / 背</b> 三视图。直接生成图片或视频,模型缺少多角度参考,角色一致性、姿态稳定性可能下降。</span>
                              <span className="pop-tip">建议:点右下 <b>AI 生成三视图</b> 先补齐三视图,再发起后续生成。</span>
                            </span>
                          </span>
                          <span className="ph-frame" id="asset-prod-thumb-label">{productName} · 主图</span>
                        </div>
                        <div className="prod-body">
                          <div className="prod-name" id="asset-prod-card-name">{productName}</div>
                          <div className="prod-cat">美妆个护</div>
                          <div className="prod-date">2026-05-15 创建</div>
                        </div>
                        <div className="prod-action" id="asset-prod-action">
                          <button className="btn-aigen" type="button" data-stop id="asset-prod-aigen-btn" disabled={loading} onClick={() => onGenerateBaseAsset("product", `${productName} 三视图`)}>
                            <svg className="ai-spark" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><path d="M12 3l1.6 4.4L18 9l-4.4 1.6L12 15l-1.6-4.4L6 9l4.4-1.6L12 3z" /><path d="M19 14l.7 1.8L21.5 16.5l-1.8.7L19 19l-.7-1.8L16.5 16.5l1.8-.7L19 14z" /></svg>
                            AI 生成三视图
                          </button>
                        </div>
                      </div>
                      <div className="prod-preview" id="asset-prod-preview">
                        <div className="prod-preview-h">// 三视图预览 · <span id="prod-preview-status">生成中</span></div>
                        <div className="placeholder prod-preview-img" id="prod-preview-img"></div>
                        <div className="prod-preview-foot" id="prod-preview-foot"></div>
                      </div>
                    </div>
                  </section>

                  <section className="asset-sec" id="asset-sec-characters">
                    <div className="sec-h"><h3>人物 · 2 个</h3><span className="spacer"></span></div>
                    <div className="asset-grid-2">
                      <div className="asset-card-2" data-asset-kind="character" data-asset-id="ch-linxi">
                        <div className="placeholder thumb-2 has-mock-media" style={mock("person-linxi.png")}><span className="ph-frame">林夕 · 都市白领</span></div>
                        <div className="body-2">
                          <div className="hstack"><strong style={{ fontSize: "13.5px" }}>主角 · 林夕</strong><span className="spacer"></span></div>
                          <div className="prompt-box" contentEditable suppressContentEditableWarning spellCheck={false} data-stop>25-30 岁都市白领,长发,穿宽松米色家居服,温柔但带点疲倦感。</div>
                          <div className="hstack" style={{ marginTop: "10px" }}><button className="btn btn-ghost btn-sm" data-stop>重跑</button><span className="spacer"></span><button className="btn btn-ghost btn-sm" data-stop>替换</button></div>
                        </div>
                      </div>
                      <div className="asset-card-2" data-asset-kind="character" data-asset-id="ch-anan">
                        <div className="placeholder thumb-2">
                          <div style={{ display: "flex", flexDirection: "column", gap: "8px", alignItems: "center" }}>
                            <div className="spinner"></div>
                            <span className="ph-frame">生成中 · 约 8s</span>
                          </div>
                        </div>
                        <div className="body-2">
                          <div className="hstack"><strong style={{ fontSize: "13.5px" }}>朋友/同事 · 阿楠</strong><span className="spacer"></span></div>
                          <div className="prompt-box" contentEditable suppressContentEditableWarning spellCheck={false} data-stop>25-30 岁同龄女性,短发,穿白色衬衫,妆容精致皮肤好,作为对比。</div>
                          <div className="hstack" style={{ marginTop: "10px" }}><button className="btn btn-ghost btn-sm" data-stop disabled>重跑</button><span className="spacer"></span><button className="btn btn-ghost btn-sm" data-stop disabled>替换</button></div>
                        </div>
                      </div>
                    </div>
                  </section>

                  <section className="asset-sec" id="asset-sec-scenes">
                    <div className="sec-h"><h3>场景 · 3 个</h3><span className="spacer"></span></div>
                    <div className="asset-grid-2">
                      <div className="asset-card-2" data-asset-kind="scene" data-asset-id="sc-desk">
                        <div className="placeholder thumb-2 has-mock-media" style={mock("scene-office.png")}><span className="ph-frame">深夜办公桌</span></div>
                        <div className="body-2">
                          <div className="hstack"><strong style={{ fontSize: "13.5px" }}>深夜办公桌</strong><span className="spacer"></span></div>
                          <div className="prompt-box" contentEditable suppressContentEditableWarning spellCheck={false} data-stop>深夜居家办公环境,木质书桌,台灯暖光,电脑屏幕亮着。</div>
                          <div className="hstack" style={{ marginTop: "10px" }}><button className="btn btn-ghost btn-sm" data-stop>重跑</button><span className="spacer"></span><button className="btn btn-ghost btn-sm" data-stop>替换</button></div>
                        </div>
                      </div>
                      <div className="asset-card-2" data-asset-kind="scene" data-asset-id="sc-bed">
                        <div className="placeholder thumb-2 has-mock-media" style={mock("scene-bedroom.png")}><span className="ph-frame">床头特写</span></div>
                        <div className="body-2">
                          <div className="hstack"><strong style={{ fontSize: "13.5px" }}>卧室床头</strong><span className="spacer"></span></div>
                          <div className="prompt-box" contentEditable suppressContentEditableWarning spellCheck={false} data-stop>米白色床品,木质床头柜,闹钟显示晚间时间。</div>
                          <div className="hstack" style={{ marginTop: "10px" }}><button className="btn btn-ghost btn-sm" data-stop>重跑</button><span className="spacer"></span><button className="btn btn-ghost btn-sm" data-stop>替换</button></div>
                        </div>
                      </div>
                      <div className="asset-card-2" data-asset-kind="scene" data-asset-id="sc-subway">
                        <div className="placeholder thumb-2">
                          <div style={{ display: "flex", flexDirection: "column", gap: "6px", alignItems: "center" }}>
                            <div className="fail-icon">!</div>
                            <span className="ph-frame">生成失败</span>
                          </div>
                        </div>
                        <div className="body-2">
                          <div className="hstack"><strong style={{ fontSize: "13.5px" }}>通勤地铁</strong><span className="spacer"></span><span className="pill err"><span className="dot"></span>失败</span></div>
                          <div className="prompt-box" contentEditable suppressContentEditableWarning spellCheck={false} data-stop>早高峰地铁车厢,光线偏冷,年轻通勤族,氛围紧张。</div>
                          <div className="hstack" style={{ marginTop: "10px" }}><button className="btn btn-ghost btn-sm" data-stop>重跑</button><span className="spacer"></span><button className="btn btn-ghost btn-sm" data-stop>替换</button></div>
                        </div>
                      </div>
                    </div>
                  </section>
                </div>
              </div>

              <div className="stage-foot">
                <div className="info"><span className="mono">[ 已确认 ¥0.85 · 待生成 ¥0.20 · 失败 ¥0(不扣) ]</span></div>
                <div className="hstack">
                  <button className="btn" type="button" onClick={() => goStage(1)}><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M19 12H5M12 19l-7-7 7-7" /></svg> 返回脚本</button>
                  <button className="btn btn-primary btn-lg" type="button" onClick={() => goStage(3)}>确认资产,进入故事板 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M12 5l7 7-7 7" /></svg></button>
                </div>
              </div>
            </section>
          )}
          {viewStage === 3 && (
            <section className="stage active" data-stage-pane="3">
              <div className="stage-storyboard">
                <div className="sb-canvas">
                  <div className="sb-scenes-col" id="sb-scenes-row">
                    {SB_SCENES.map((scene) => (
                      <div className={`sb-scene-thumb${scene.sid === "sc1" ? " selected" : ""}`} key={scene.sid} data-sid={scene.sid}>
                        <div className="placeholder has-mock-media" style={mock(scene.img)}><span className="ph-frame">{scene.frame}</span></div>
                        <div className="nm">{scene.nm}</div>
                        <div className="sub">{scene.sub}</div>
                      </div>
                    ))}
                  </div>
                  <div className="placeholder sb-main-img has-mock-media" id="sb-main-img" style={mock("cover-mask-v3.png")}><span className="ph-frame">场 1 · 深夜办公桌 · v1</span></div>
                </div>

                <div className="sb-side">
                  <div className="pane" style={{ padding: "18px" }}>
                    <div className="hstack" style={{ marginBottom: "10px" }}>
                      <strong style={{ fontSize: "14px" }}>故事板 · <span id="sb-side-scene">场 1</span></strong>
                      <span className="spacer"></span>
                      <span className="pill ok"><span className="dot"></span>已生成</span>
                    </div>
                    <div className="muted-2" style={{ fontSize: "12px", lineHeight: 1.55, marginBottom: "10px" }}>整张故事板由 image-2 一次性输出,包含画面 + 镜头说明。</div>
                    <div className="sb-rerun-note">
                      <span className="warn-ic" aria-hidden="true">
                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z" /><path d="M12 9v4M12 17h.01" /></svg>
                      </span>
                      <div className="note-copy"><strong>仅支持整张重跑</strong> · 不能局部改某一镜。如需调单镜,先在 <a href="#stage-1" onClick={(event) => { event.preventDefault(); goStage(1); }}>Stage 1 脚本</a> 改镜头描述,再回此处整张重跑。</div>
                    </div>
                    <div className="muted mono" style={{ fontSize: "11px", fontWeight: 500, marginBottom: "6px", letterSpacing: ".04em" }}>// 本场提示词</div>
                    <div className="prompt-edit" contentEditable suppressContentEditableWarning id="sb-prompt-edit">{SB_PROMPT}</div>
                    <div className="sb-stage-actions">
                      <button className="pill-cta heat" type="button" id="sb-rerun-btn" disabled={loading} onClick={() => onGenerateStoryboard(storyboardPrompt)}>
                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M4 12a8 8 0 0 1 14-5.5L21 9" /><path d="M21 4v5h-5" /><path d="M20 12a8 8 0 0 1-14 5.5L3 15" /><path d="M3 20v-5h5" /></svg>
                        整张重跑
                      </button>
                      <span className="spacer"></span>
                      <span className="muted-2 mono" style={{ fontSize: "11px", alignSelf: "center" }}>~¥0.45/场</span>
                    </div>
                    <div className="sb-history">
                      <div className="sb-history-h">// 历史版本(<span id="sb-history-ct">1</span>)</div>
                      <div className="sb-history-row" id="sb-history-row">
                        <div className="sb-history-thumb current" data-vi="0">
                          <div className="placeholder has-mock-media" style={mock("cover-mask-final.png")}><span className="ph-frame">v1</span></div>
                          <div className="ts">14:02</div>
                        </div>
                      </div>
                    </div>
                    <div className="divider" style={{ marginTop: "16px" }}></div>
                    <div className="muted mono" style={{ fontSize: "11px", fontWeight: 500, marginBottom: "8px", letterSpacing: ".04em" }}>// 绑定的资产</div>
                    <div style={{ display: "flex", gap: "6px", flexWrap: "wrap" }} id="sb-bound-assets">
                      <span className="asset-tag"><span className="dotc"></span>林夕(人物)</span>
                      <span className="asset-tag"><span className="dotc"></span>深夜办公桌(场景)</span>
                    </div>
                  </div>
                </div>
              </div>

              <div className="stage-foot">
                <div className="info"><span className="mono">[ image-2 单场 ¥0.45 · 累计 ¥1.35 · 整张重跑,失败不扣 ]</span></div>
                <div className="hstack">
                  <button className="btn" type="button" onClick={() => goStage(2)}><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M19 12H5M12 19l-7-7 7-7" /></svg> 返回资产</button>
                  <button className="btn btn-primary btn-lg" type="button" onClick={() => goStage(4)}>确认故事板,开始生成视频 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M12 5l7 7-7 7" /></svg></button>
                </div>
              </div>
            </section>
          )}
          {viewStage === 4 && (
            <section className="stage active" data-stage-pane="4">
              <div className="queue-bar">
                <div>
                  <div style={{ fontSize: "14px", fontWeight: 600 }}>视频生成 · 3 / 3 完成</div>
                  <div className="muted-2 mono" style={{ fontSize: "11px", marginTop: "3px", letterSpacing: ".02em" }}>// 每场 Seedance 约 <span id="seedance-avg">15</span> 秒 · 已完成所有场次</div>
                </div>
                <div className="bar-wrap"><span style={{ width: "100%" }}></span></div>
                <span className="muted mono" style={{ fontSize: "12px" }}>100%</span>
                <button className="btn btn-sm" type="button" disabled={loading} onClick={() => onSubmitAllVideos(videoPrompt)}>↻ 全部重跑</button>
                <button className="btn btn-sm" type="button">
                  <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={{ marginRight: "4px" }}><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" /><path d="M17 8l-5-5-5 5" /><path d="M12 3v12" /></svg>
                  上传视频
                </button>
              </div>

              <div className="video-grid" id="video-grid">
                {VIDEO_CARDS.map((card) => (
                  <div className="video-card" key={card.vid} data-video-id={card.vid}>
                    <div className="placeholder video-thumb has-mock-media" style={mock(card.img)}>
                      <span className="ph-frame">{card.frame}</span>
                      <div className="play"><div className="btn-play"><Play size={14} fill="currentColor" /></div></div>
                    </div>
                    <div className="body">
                      <div className="video-card-head"><strong className="video-card-title">{card.title}</strong><span className="pill ok"><span className="dot"></span>完成</span></div>
                      <div className="video-meta">{card.meta}</div>
                      <div className="video-actions">
                        <button className="btn btn-ghost btn-sm" type="button" data-vstop>重跑</button>
                        <span className="spacer"></span>
                        <button className="btn btn-ghost btn-sm" type="button" data-vstop>下载</button>
                      </div>
                    </div>
                  </div>
                ))}
              </div>

              <div className="stage-foot">
                <div className="info"><span className="mono">[ 已完成 3 场 · 累计 ¥1.35 · 总时长 <span id="seedance-total">40</span>s · 失败不扣 · 通过后扣 ]</span></div>
                <div className="hstack">
                  <button className="btn" type="button" onClick={() => goStage(3)}><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M19 12H5M12 19l-7-7 7-7" /></svg> 返回故事板</button>
                  <button className="btn btn-primary btn-lg" type="button" onClick={() => goStage(5)}>确认视频,进入拼接 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M12 5l7 7-7 7" /></svg></button>
                </div>
              </div>
            </section>
          )}
          {viewStage === 5 && (
            <section className="stage active" data-stage-pane="5">
              <div className="editor">
                <div className="editor-preview">
                  <div className="canvas has-mock-media" id="ed-canvas" style={{ backgroundImage: "url(/exact/assets/mock/cover-mask-final.png)" }}><span id="ed-canvas-label">9:16 预览 · 1080×1920</span></div>
                  <div className="controls">
                    <button className="ctl-btn" type="button" id="ed-prev-btn" title="上一帧 (←)"><svg width="14" height="14" viewBox="0 0 16 16"><path d="M3 3v10l4-5zM9 3v10l4-5z" fill="currentColor" /></svg></button>
                    <button className="ctl-btn" type="button" id="ed-play-btn" title="播放 / 暂停 (空格)"><svg id="ed-play-icon" width="16" height="16" viewBox="0 0 16 16"><path d="M5 4l7 4-7 4z" fill="currentColor" /></svg></button>
                    <button className="ctl-btn" type="button" id="ed-next-btn" title="下一帧 (→)"><svg width="14" height="14" viewBox="0 0 16 16"><path d="M13 3v10l-4-5zM7 3v10l-4-5z" fill="currentColor" /></svg></button>
                    <span className="muted mono" style={{ fontSize: "12px", marginLeft: "8px" }}><span id="ed-cur-time">00:00.00</span> / <span id="ed-total-time">00:15.00</span></span>
                  </div>
                </div>

                <div className="editor-props">
                  <div className="props-tabs"><div className="active">字幕</div><div>转场</div><div>BGM</div></div>
                  <div className="muted mono" style={{ fontSize: "11px", fontWeight: 500, marginBottom: "8px", letterSpacing: ".04em" }}>// 字幕样式</div>
                  <div className="style-swatch">
                    <div className="swatch-card selected"><div className="demo">真实分享</div><div className="nm">朴素白底</div></div>
                    <div className="swatch-card"><div className="demo b">真实分享</div><div className="nm">影视黑底</div></div>
                    <div className="swatch-card"><div className="demo c">真实分享</div><div className="nm">手写描边</div></div>
                    <div className="swatch-card"><div className="demo d">真实分享</div><div className="nm">综艺暖黄</div></div>
                  </div>
                  <div className="divider"></div>
                  <div className="muted mono" style={{ fontSize: "11px", fontWeight: 500, marginBottom: "8px", letterSpacing: ".04em" }}>// 当前选中(<span id="ed-inspect-name">未选</span>)</div>
                  <div className="props-row"><span className="k">起始</span><input className="input-mini" id="ed-inspect-start" defaultValue="—" /></div>
                  <div className="props-row"><span className="k">时长</span><input className="input-mini" id="ed-inspect-dur" defaultValue="—" /></div>
                  <div className="props-row"><span className="k">音量</span><input className="input-mini" defaultValue="100" /></div>
                  <div className="props-row"><span className="k">速度</span><input className="input-mini" defaultValue="1.0x" /></div>
                  <div className="props-row"><span className="k">入场</span><span className="mono" style={{ fontSize: "11.5px" }}>交叉淡化</span></div>
                  <div className="divider"></div>
                  <div className="muted mono" style={{ fontSize: "11px", fontWeight: 500, marginBottom: "8px", letterSpacing: ".04em" }}>// BGM</div>
                  <div className="props-row" style={{ borderBottom: 0 }}><span style={{ fontSize: "12px", flex: 1 }}>温柔治愈钢琴 · 0:42</span><button className="btn btn-ghost btn-sm" type="button">替换</button></div>
                </div>

                <div className="timeline" id="ed-timeline">
                  <div className="tl-toolbar">
                    <button className="tl-action" type="button" title="撤销"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M3 7v6h6" /><path d="M21 17a9 9 0 0 0-15-6.7L3 13" /></svg></button>
                    <button className="tl-action" type="button" title="重做"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M21 7v6h-6" /><path d="M3 17a9 9 0 0 1 15-6.7L21 13" /></svg></button>
                    <span className="tl-sep"></span>
                    <button className="tl-action" type="button" title="在播放头处分割选中片段"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><circle cx="6" cy="6" r="3" /><circle cx="6" cy="18" r="3" /><path d="M20 4L8.12 15.88" /><path d="M14.47 14.48L20 20" /><path d="M8.12 8.12L12 12" /></svg>分割</button>
                    <button className="tl-action" type="button" title="复制选中片段"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" /><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" /></svg>复制</button>
                    <button className="tl-action danger" type="button" title="删除选中片段 (Delete)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M3 6h18" /><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" /><path d="M19 6l-1.5 14a2 2 0 0 1-2 1.8H8.5a2 2 0 0 1-2-1.8L5 6" /></svg>删除</button>
                    <span className="spacer"></span>
                    <div className="tl-zoom"><span className="lbl">// zoom</span><input type="range" min={50} max={200} defaultValue={100} /></div>
                  </div>

                  <div className="tl-ruler">
                    <div className="l">// time</div>
                    <div className="rule-track" id="ed-ruler">
                      {ED_RULER.map((tick, i) => (
                        <span className={`tick ${tick.major ? "major" : "minor"}`} key={i} style={{ left: tick.left }}>{tick.t && <span className="t">{tick.t}</span>}</span>
                      ))}
                    </div>
                  </div>

                  <div className="tl-track video-track">
                    <div className="label video"><span className="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><rect x="2" y="2" width="20" height="20" rx="2.18" /><path d="M7 2v20M17 2v20M2 12h20M2 7h5M2 17h5M17 17h5M17 7h5" /></svg></span>视频</div>
                    <div className="lane" id="ed-lane-video" data-track="video">
                      {edLayout(ED_VIDEO_CLIPS).map((clip) => (
                        <div className="clip video" key={clip.n} data-track="video" data-label={clip.lbl} style={{ left: `${clip.leftPct}%`, width: `${clip.widthPct}%` }}>
                          <span className="frames">{Array.from({ length: clip.dur + 1 }).map((_, i) => <span className="fr" key={i}></span>)}</span>
                          <span className="num">{clip.n}</span><span className="lbl">{clip.lbl}</span>
                        </div>
                      ))}
                    </div>
                  </div>

                  <div className="tl-track subtitle-track">
                    <div className="label subtitle"><span className="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M4 7V4h16v3" /><path d="M9 20h6" /><path d="M12 4v16" /></svg></span>字幕</div>
                    <div className="lane" id="ed-lane-subtitle" data-track="subtitle">
                      {edLayout(ED_SUB_CLIPS).map((clip, i) => (
                        <div className="clip subtitle" key={i} data-track="subtitle" data-label={clip.lbl} style={{ left: `${clip.leftPct}%`, width: `${clip.widthPct}%` }}><span className="lbl">{clip.lbl}</span></div>
                      ))}
                      <div className="playhead" id="ed-playhead" style={{ left: "0%" }}><span className="ph-grab"></span></div>
                    </div>
                  </div>

                  <div className="tl-track bgm-track">
                    <div className="label bgm"><span className="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M9 18V5l12-2v13" /><circle cx="6" cy="18" r="3" /><circle cx="18" cy="16" r="3" /></svg></span>BGM</div>
                    <div className="lane">
                      <div className="clip bgm" data-track="bgm" data-label="温柔治愈钢琴" style={{ left: "0%", width: "100%" }}>
                        <span className="wave"><svg viewBox="0 0 600 20" preserveAspectRatio="none" fill="currentColor">{ED_WAVE.map(([y, h], i) => <rect key={i} x={i * 4} y={y} width="2" height={h} />)}</svg></span>
                        <span className="lbl">温柔治愈钢琴 · 0:42(循环 1 次,淡入淡出)</span>
                      </div>
                    </div>
                  </div>
                </div>
              </div>

              <div className="stage-foot">
                <div className="info"><span className="mono">[ 合成预估 ~30s · 拼接 / 导出全程 0 token · 已结算 ¥1.39 ]</span></div>
                <div className="hstack">
                  <button className="btn" type="button" onClick={() => goStage(4)}><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M19 12H5M12 19l-7-7 7-7" /></svg> 返回片段</button>
                  <button className="btn" type="button">保存草稿</button>
                  <button className="btn btn-primary btn-lg" type="button" onClick={onSubmitExport}>导出 MP4 · 1080P 9:16 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M12 4v12m0 0l-5-5m5 5l5-5M4 20h16" /></svg></button>
                </div>
              </div>
            </section>
          )}
        </div>
      </main>
    </div>
  );
}
