import { useEffect, useMemo, useState } from "react";
import type { CSSProperties, FormEvent } from "react";
import type { Product, Project } from "../types";
import type { Page } from "./route-config";
import { ConfirmModal, EmptyPanel } from "../components/overlays";
import "../project-wizard-page.css";

// 时长 / 脚本风格 / 人设 — 与 projects-new.html 基线对齐(创建页仅作视觉选择,
// 脚本走向细节进入 Stage 1;onCreate 契约只携带 name + product)。
const WIZ_DURATIONS = [
  { id: "0-10", label: "0-10 秒", shots: [3, 4], tag: "黄金完播" },
  { id: "0-15", label: "0-15 秒", shots: [4, 5], tag: "完播率最佳" },
  { id: "0-30", label: "0-30 秒", shots: [6, 8], tag: "卖点详解" },
  { id: "0-60", label: "0-60 秒", shots: [10, 12], tag: "故事化" }
];
const WIZ_STYLES = [
  { id: "pain", name: "痛点种草", note: "用户痛点切入,以「我懂你」的口吻引出产品。", tag: "最常用" },
  { id: "review", name: "开箱测评", note: "朋友式分享,从开箱到使用感受娓娓道来。", tag: "" },
  { id: "compare", name: "对比展示", note: "「用前 vs 用后 / 同类 vs 本品」直观呈现。", tag: "" }
];
const WIZ_PERSONAS = [
  { id: "urban", name: "都市白领女性", sub: "25-30 岁", metric: "大盘消费力", dur: "0-15", style: "pain" },
  { id: "bestie", name: "闺蜜种草", sub: "邻家女孩", metric: "复购最高", dur: "0-15", style: "pain" },
  { id: "ceo", name: "总裁亲选", sub: "创始人 IP", metric: "30 万销额案例", dur: "0-30", style: "pain" },
  { id: "reviewer", name: "专业测评师", sub: "垂类达人", metric: "互动 +30%", dur: "0-30", style: "review" },
  { id: "mom", name: "实用宝妈", sub: "家庭决策者", metric: "母婴/家清稳", dur: "0-30", style: "pain" },
  { id: "genz", name: "学生党", sub: "Z 世代 18-24", metric: "平价快消", dur: "0-10", style: "compare" }
];

const WIZ_PAGE_SIZE = 7; // 4 列 × 2 行 = 8 格,首格为「创建新商品」→ 每页 7 商品

export function ProjectWizardPage({ products, onBack, onCreate }: {
  products: Product[];
  onBack: () => void;
  onCreate: (payload: { name: string; product: string }) => Promise<unknown> | void;
}) {
  const [productId, setProductId] = useState(products[0]?.id || "");
  const product = products.find((item) => item.id === productId) || products[0];
  const [name, setName] = useState(() => `${(products[0]?.title || "商品").split(" ")[0]} · 痛点种草 · v1`);

  // Step 1 · 商品选择器本地交互态
  const [pickSearch, setPickSearch] = useState("");
  const [pickCat, setPickCat] = useState("全部");
  const [catOpen, setCatOpen] = useState(false);
  const [pickView, setPickView] = useState<"grid" | "list">("grid");
  const [pickPage, setPickPage] = useState(1);

  // Step 2 · 配置(视觉选择,详见 Stage 1)
  const [duration, setDuration] = useState<string | null>("0-15");
  const [scriptStyle, setScriptStyle] = useState<string | null>("pain");
  const [persona, setPersona] = useState<string | null>(null);
  const [recoDismissed, setRecoDismissed] = useState(false);
  const [points, setPoints] = useState<Record<string, boolean>>({});

  useEffect(() => {
    if (!productId && products[0]) setProductId(products[0].id);
  }, [productId, products]);

  // 分类清单
  const cats = useMemo(
    () => ["全部", ...Array.from(new Set(products.map((p) => p.category || "未分类")))],
    [products]
  );

  // 筛选 + 排序后的商品
  const filtered = useMemo(() => {
    const q = pickSearch.trim().toLowerCase();
    return products.filter((p) => {
      const cat = p.category || "未分类";
      if (pickCat !== "全部" && cat !== pickCat) return false;
      if (q) {
        const blob = `${p.title} ${cat} ${(p.selling_points || []).map((s) => s.title).join(" ")}`.toLowerCase();
        if (!blob.includes(q)) return false;
      }
      return true;
    });
  }, [products, pickSearch, pickCat]);

  const hasFilter = !!pickSearch || pickCat !== "全部";
  const total = filtered.length;
  const totalPages = Math.max(1, Math.ceil(total / WIZ_PAGE_SIZE));
  const cur = Math.min(pickPage, totalPages);
  const pageList = filtered.slice((cur - 1) * WIZ_PAGE_SIZE, cur * WIZ_PAGE_SIZE);

  function selectProduct(id: string) {
    setProductId(id);
    const p = products.find((item) => item.id === id);
    if (p) {
      const seed: Record<string, boolean> = {};
      (p.selling_points || []).forEach((sp) => { seed[sp.title] = false; });
      setPoints(seed);
    }
  }

  function clearPickFilters() {
    setPickSearch("");
    setPickCat("全部");
    setPickPage(1);
  }

  function applyPreset() {
    const p = WIZ_PERSONAS.find((item) => item.id === persona);
    if (!p) return;
    setDuration(p.dur);
    setScriptStyle(p.style);
    setRecoDismissed(false);
  }

  const personaObj = WIZ_PERSONAS.find((p) => p.id === persona);
  const durObj = WIZ_DURATIONS.find((d) => d.id === duration);
  const styleObj = WIZ_STYLES.find((s) => s.id === scriptStyle);
  const showReco =
    !!personaObj && !!duration && !!scriptStyle && !recoDismissed &&
    (personaObj.dur !== duration || personaObj.style !== scriptStyle);
  const recoDur = personaObj && WIZ_DURATIONS.find((d) => d.id === personaObj.dur);
  const recoStyle = personaObj && WIZ_STYLES.find((s) => s.id === personaObj.style);

  const product1Done = !!productId;
  const config2Done = !!duration && !!styleObj && name.trim().length >= 2;
  const canStart = product1Done && config2Done;

  function submit(event: FormEvent) {
    event.preventDefault();
    if (!canStart || !product) return;
    void onCreate({ name: name.trim() || `${product.title} · 短视频`, product: product.id });
  }

  const productCover = (p: Product): CSSProperties | undefined => {
    const file = p.cover_asset || p.images?.find((img) => img.is_primary)?.asset || p.images?.[0]?.asset;
    return file ? ({ ["--mock-media-url"]: `url(${file})` } as CSSProperties) : undefined;
  };

  return (
    <section className="project-wizard-page">
      <div className="page-head">
        <div>
          <h1>新建项目</h1>
          <div className="sub"><span className="mono">// 商品 → 配置 · 2 步开始生成</span></div>
        </div>
        <div className="actions">
          <button className="btn btn-ghost" type="button" onClick={onBack}>退出</button>
        </div>
      </div>

      <form className="wizard" onSubmit={submit}>
        {/* ── 左侧步骤轨 ── */}
        <nav className="steps" aria-label="新建项目步骤">
          <div className={`step ${product1Done ? "done" : "active"}`}>
            <div className="num">{product1Done ? (
              <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="3 8 7 12 13 4" /></svg>
            ) : "1"}</div>
            <div>
              <div className="label">选择商品</div>
              <div className="desc">{product?.title || "未选择"}</div>
            </div>
          </div>
          <div className={`step ${config2Done ? "done" : product1Done ? "active" : ""}`}>
            <div className="num">{config2Done ? (
              <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="3 8 7 12 13 4" /></svg>
            ) : "2"}</div>
            <div>
              <div className="label">项目配置</div>
              <div className="desc">{durObj && styleObj ? `${durObj.label} · ${styleObj.name}` : "时长 · 风格 · 人物"}</div>
            </div>
          </div>
        </nav>

        {/* ── 主体 ── */}
        <div className="wiz-body">
          {/* Step 1 · 商品选择 */}
          <section className="step-pane-wrap">
            <div className="wiz-pane">
              <div className="wiz-step-h">
                <h2>第 1 步 · 选择商品</h2>
                <p>从商品库选一个 SKU。它的主图与卖点会被 LLM 作为脚本/资产生成的素材。</p>
              </div>

              <div className="pp-toolbar">
                <div className="search-inline">
                  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5"><circle cx="11" cy="11" r="7" /><path d="m21 21-4.3-4.3" /></svg>
                  <input type="text" placeholder="搜索商品名称、标签" value={pickSearch} onChange={(event) => { setPickSearch(event.target.value); setPickPage(1); }} />
                </div>
                <div className={`pp-chip-wrap${catOpen ? " open" : ""}`}>
                  <button className={`pp-chip${pickCat !== "全部" ? " active" : ""}`} type="button" onClick={() => setCatOpen((open) => !open)}>
                    <span>{pickCat === "全部" ? "全部分类" : pickCat}</span>
                    <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M4 6l4 4 4-4" /></svg>
                  </button>
                  <div className="pp-menu">
                    {cats.map((c) => (
                      <div className={`mi${pickCat === c ? " selected" : ""}`} key={c} onClick={() => { setPickCat(c); setPickPage(1); setCatOpen(false); }}>
                        <svg className="mi-check" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="2.6"><polyline points="3 8 7 12 13 4" /></svg>
                        <span>{c}</span>
                      </div>
                    ))}
                  </div>
                </div>
                {hasFilter && (
                  <button className="pp-clear" type="button" onClick={clearPickFilters}>
                    <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M4 4l8 8M12 4l-8 8" /></svg>
                    清空筛选
                  </button>
                )}
              </div>

              <div className="pp-result-meta">// 显示 {pageList.length} / {total} 个商品{hasFilter ? " (已筛选)" : ""}</div>

              <div className={`pp-grid${pickView === "list" ? " list-view" : ""}`}>
                <div className="pp-create-card" onClick={onBack}>
                  <div className="pc-plus"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M12 5v14M5 12h14" /></svg></div>
                  <div className="pc-t">创建新商品</div>
                  <div className="pc-d">// 在此添加一个新商品</div>
                </div>
                {total === 0 ? (
                  <div className="pp-empty">// NO MATCH<br />没有符合筛选条件的商品 <span className="reset" onClick={clearPickFilters}>[ 清空筛选 ]</span></div>
                ) : (
                  pageList.map((p) => (
                    <div className={`product-card${productId === p.id ? " selected" : ""}`} key={p.id} onClick={() => selectProduct(p.id)}>
                      <div className={`placeholder product-thumb${productCover(p) ? " has-mock-media" : ""}`} style={productCover(p)}><span className="ph-frame">{p.title} · 1200×800</span></div>
                      <div className="product-body">
                        <div className="product-name">{p.title}</div>
                        <div className="product-cat">{p.category || "未分类"}</div>
                        <div className="product-date">{(p.created_at || "").slice(0, 10)} 创建</div>
                      </div>
                    </div>
                  ))
                )}
              </div>

              {total > WIZ_PAGE_SIZE && (
                <div className="pp-pager">
                  <span className="total">共 {total} 条</span>
                  <div className="pages">
                    <button type="button" disabled={cur === 1} onClick={() => setPickPage(cur - 1)}>‹</button>
                    {Array.from({ length: totalPages }, (_, i) => i + 1).map((n) => (
                      <button type="button" key={n} className={n === cur ? "active" : ""} onClick={() => setPickPage(n)}>{n}</button>
                    ))}
                    <button type="button" disabled={cur === totalPages} onClick={() => setPickPage(cur + 1)}>›</button>
                  </div>
                  <span className="page-size">每页 {WIZ_PAGE_SIZE} 条</span>
                </div>
              )}

              <div className="pp-bottom-tip">
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9" /><path d="M12 8v5M12 16h.01" /></svg>
                <span>找不到想要的商品?可<a onClick={onBack}>创建新商品</a>,或前往 <a onClick={onBack}>商品库 · 管理商品</a></span>
              </div>

              {products.length === 0 && <EmptyPanel title="还没有商品" action="去创建商品" onAction={onBack} />}
            </div>
          </section>

          {/* Step 2 · 项目配置 */}
          <section className="step-pane-wrap">
            <div className="wiz-pane">
              <div className="wiz-step-h">
                <h2>第 2 步 · 项目配置</h2>
                <p>这些设置会影响 LLM 生成脚本的方向,确认后会进入流水线第 1 步(脚本生成)。</p>
              </div>

              <div className="config-row">
                <div className="field">
                  <label className="field-label">项目名称<span className="req">*</span></label>
                  <input className="input" value={name} onChange={(event) => setName(event.target.value)} />
                </div>
                <div className="field">
                  <label className="field-label">视频时长<span className="req">*</span></label>
                  <select className="select duration-select" value={duration || ""} onChange={(event) => setDuration(event.target.value || null)}>
                    <option value="" disabled>选择时长</option>
                    {WIZ_DURATIONS.map((d) => (
                      <option value={d.id} key={d.id}>{d.label} · {d.shots[0]}-{d.shots[1]} 镜</option>
                    ))}
                  </select>
                </div>
              </div>

              <div className="field">
                <label className="field-label">脚本风格</label>
                <div className="opt-row cols-4">
                  {WIZ_STYLES.map((s) => (
                    <div className={`opt-card${scriptStyle === s.id ? " selected" : ""}`} key={s.id} onClick={() => setScriptStyle(s.id)}>
                      <h4>{s.name}</h4>
                      <div className="note">{s.note}</div>
                      {s.tag && <span className="badge">[ {s.tag} ]</span>}
                    </div>
                  ))}
                </div>
              </div>

              <div className="field">
                <label className="field-label">人物设定</label>
                <div className="opt-row cols-6">
                  {WIZ_PERSONAS.map((p) => (
                    <div className={`opt-card${persona === p.id ? " selected" : ""}`} key={p.id} onClick={() => { setPersona(p.id); setRecoDismissed(false); }}>
                      <h4>{p.name}</h4>
                      <div className="sub">{p.sub}</div>
                      <div className="metric"><span className="val">{p.metric}</span></div>
                    </div>
                  ))}
                </div>

                {showReco && recoDur && recoStyle && durObj && styleObj && (
                  <div className="reco-bubble">
                    <span className="ic">
                      <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9" /><path d="M12 16v-4M12 8h.01" /></svg>
                    </span>
                    <div className="txt">
                      <span>抖音同人设 TOP 视频更常用 <strong>{recoDur.label}</strong> + <strong>{recoStyle.name}</strong></span>
                      <span className="meta">当前 {durObj.label} · {styleObj.name} → 推荐换为同人设最优组合</span>
                    </div>
                    <button className="btn-apply" type="button" onClick={applyPreset}>一键套用</button>
                    <button className="dismiss" type="button" onClick={() => setRecoDismissed(true)} aria-label="忽略">
                      <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M6 6l12 12M6 18L18 6" /></svg>
                    </button>
                  </div>
                )}
              </div>

              {Object.keys(points).length > 0 && (
                <div className="field" style={{ marginBottom: 0 }}>
                  <label className="field-label">关键卖点(可勾选要重点突出的)</label>
                  <div className="theme-pill-row">
                    {Object.entries(points).map(([k, v]) => (
                      <button className={`theme-pill${v ? " active" : ""}`} type="button" key={k} aria-pressed={v} onClick={() => setPoints((prev) => ({ ...prev, [k]: !prev[k] }))}>
                        {v && <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="3 8 7 12 13 4" /></svg>}
                        <span>{k}</span>
                      </button>
                    ))}
                  </div>
                </div>
              )}
            </div>
          </section>

          {/* ── 底部「开始」CTA ── */}
          <div className="wiz-start-bar">
            <button className={`btn-start${canStart ? "" : " disabled"}`} type="submit" disabled={!canStart}>
              <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M5 3l14 9-14 9V3z" /></svg>
              <span>开始</span>
            </button>
          </div>
        </div>
      </form>
    </section>
  );
}

// 对齐 api-bridge:阶段编号 / 状态分桶 / 友好标签 / pill 类
const PROJ_STAGE_NO: Record<string, number> = { script: 1, base_assets: 2, storyboard: 3, video: 4, export: 5 };
function projStageNo(project: Project) { return project.status === "completed" ? 5 : (PROJ_STAGE_NO[project.current_stage] || 1); }
function projBucket(project: Project) { return project.status === "completed" ? "done" : project.status === "failed" ? "fail" : "wip"; }
function projStatusLabel(project: Project) {
  return ({ draft: "脚本待生成", scripting: "脚本生成中", asseting: "基础资产生成中", storyboarding: "故事板生成中", videoing: "视频片段生成中", exporting: "导出中", completed: "已完成", failed: "失败" } as Record<string, string>)[project.status] || "进行中";
}
function projPillClass(project: Project) { return project.status === "completed" ? "ok" : project.status === "failed" ? "fail" : "info"; }
function projDate(project: Project) { return (project.updated_at || "").slice(0, 10); }
// 复刻 mock-media coverFor:按项目名关键词映射封面图(无匹配 → 占位)
function projCover(name: string): string {
  const t = name.replace(/\s+/g, "");
  if (/蓝牙|耳机|南卡/.test(t)) return "cover-earbuds.png";
  if (/速食|牛肉面|泡面|面条/.test(t)) return "cover-noodle.png";
  if (/防晒/.test(t)) return "cover-sunscreen.png";
  if (/咖啡|冻干/.test(t)) return "cover-coffee.png";
  if (/空气炸锅|小熊/.test(t)) return "cover-air-fryer.png";
  if (/瑜伽裤|露露/.test(t)) return "cover-yoga.png";
  if (/v1|final|已完成|成片|敷面膜|化妆台/.test(t)) return "cover-mask-final.png";
  if (/面膜|补水|玻尿酸|透真/.test(t)) return "cover-mask-v3.png";
  return "";
}
const projMock = (file: string): CSSProperties => ({ ["--mock-media-url"]: `url(/exact/assets/mock/${file})` } as CSSProperties);

const PROJ_TABS: Array<{ filter: "all" | "wip" | "done" | "fail"; label: string }> = [
  { filter: "all", label: "全部" }, { filter: "wip", label: "进行中" }, { filter: "done", label: "已完成" }, { filter: "fail", label: "失败" }
];

export function ProjectsPage({ products, projects, navigate, openPipeline, onDelete }: {
  products: Product[];
  projects: Project[];
  navigate: (page: Page) => void;
  onCreate: (payload: { name: string; product: string }) => Promise<unknown> | void;
  openPipeline: (projectId: string) => void;
  onDelete: (projectId: string) => Promise<unknown> | void;
}) {
  const [view, setView] = useState<"list" | "grid">("list");
  const [tab, setTab] = useState<"all" | "wip" | "done" | "fail">("all");
  const [query, setQuery] = useState("");
  const [deleteTarget, setDeleteTarget] = useState<Project | null>(null);
  const productTitle = (id: string) => products.find((product) => product.id === id)?.title || "商品";

  const counts = {
    all: projects.length,
    wip: projects.filter((p) => projBucket(p) === "wip").length,
    done: projects.filter((p) => projBucket(p) === "done").length,
    fail: projects.filter((p) => projBucket(p) === "fail").length
  };
  const filtered = projects.filter((project) => {
    if (tab !== "all" && projBucket(project) !== tab) return false;
    return `${project.name} ${productTitle(project.product)}`.toLowerCase().includes(query.toLowerCase());
  });

  async function confirmDelete() {
    if (!deleteTarget) return;
    await onDelete(deleteTarget.id);
    setDeleteTarget(null);
  }

  return (
    <section className="projects-page">
      <div className="page-head">
        <div>
          <h1>视频项目</h1>
          <div className="sub"><span className="mono">// {counts.all} 个 · {counts.wip} 进行中 · {counts.done} 完成 · {counts.fail} 失败</span></div>
        </div>
        <div className="actions">
          <button className="btn" type="button" id="proj-manage-btn">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><path d="m3 7 2 2 4-4" /><path d="m3 17 2 2 4-4" /><path d="M13 6h8" /><path d="M13 12h8" /><path d="M13 18h8" /></svg>
            <span className="proj-manage-label">管理项目</span>
          </button>
          <button className="btn btn-primary btn-lg btn-create" type="button" onClick={() => navigate("projectWizard")}>
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="m12.3 3.5 3 4" /><path d="M20.2 6 3 11l-.9-2.4a2 2 0 0 1 1.3-2.5l13.5-4a2 2 0 0 1 2.5 1.3Z" /><path d="m6.2 5.3 3.1 3.9" /><path d="M3 11h18v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Z" /></svg>
            新建项目
          </button>
        </div>
      </div>

      <div className="tabs" id="status-tabs">
        {PROJ_TABS.map((t) => (
          <div className={`tab${tab === t.filter ? " active" : ""}`} key={t.filter} data-filter={t.filter} onClick={() => setTab(t.filter)}>{t.label} <span className="count">{counts[t.filter]}</span></div>
        ))}
      </div>

      <div className="toolbar">
        <div className="search-inline">
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5"><circle cx="11" cy="11" r="7" /><path d="m21 21-4.3-4.3" /></svg>
          <input className="input" id="search-input" placeholder="搜索项目名称、商品" value={query} onChange={(event) => setQuery(event.target.value)} />
        </div>
        <div className="chip-wrap" data-key="product"><button className="chip" type="button"><span className="chip-label">商品品类</span> <svg className="caret" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M4 6l4 4 4-4" /></svg></button></div>
        <div className="chip-wrap" data-key="source"><button className="chip" type="button"><span className="chip-label">脚本来源</span> <svg className="caret" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M4 6l4 4 4-4" /></svg></button></div>
        <div className="chip-wrap" data-key="time"><button className="chip" type="button"><span className="chip-label">创建时间</span> <svg className="caret" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M4 6l4 4 4-4" /></svg></button></div>
        <span className="spacer"></span>
        <div className="view-toggle">
          <button className={view === "grid" ? "active" : ""} type="button" data-view="grid" onClick={() => setView("grid")}>
            <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5"><rect x="2" y="2" width="5" height="5" /><rect x="9" y="2" width="5" height="5" /><rect x="2" y="9" width="5" height="5" /><rect x="9" y="9" width="5" height="5" /></svg>
            网格
          </button>
          <button className={view === "list" ? "active" : ""} type="button" data-view="list" onClick={() => setView("list")}>
            <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M2 4h12M2 8h12M2 12h12" /></svg>
            列表
          </button>
        </div>
      </div>

      <div className="result-meta" id="result-meta">// 显示 <span className="count">{filtered.length}</span> / {projects.length} 个项目</div>

      {view === "list" ? (
        <div id="list-view">
          <table className="t">
            <thead>
              <tr>
                <th style={{ width: "32%" }}>项目</th>
                <th>商品</th>
                <th>脚本来源</th>
                <th style={{ width: "200px" }}>进度</th>
                <th>状态</th>
                <th style={{ width: "120px" }}>更新于</th>
                <th style={{ width: "60px" }}></th>
              </tr>
            </thead>
            <tbody id="list-tbody">
              {filtered.map((project) => {
                const no = projStageNo(project);
                const shots = project.video_segments.length || 4;
                const cover = projCover(project.name);
                return (
                  <tr key={project.id} data-status={projBucket(project)} data-name={project.name} onClick={() => openPipeline(project.id)}>
                    <td>
                      <div className="proj-name-cell">
                        <div className={`placeholder proj-thumb${cover ? " has-mock-media" : ""}`} style={cover ? projMock(cover) : undefined}><span className="ph-frame">9:16</span></div>
                        <div><div className="proj-name">{project.name}</div><div className="proj-sub">{shots} 镜 · 0-60s</div></div>
                      </div>
                    </td>
                    <td>{productTitle(project.product)}</td>
                    <td><span className="muted">AI 全生</span></td>
                    <td>
                      <div className="hstack">
                        <div className="prog">{[1, 2, 3, 4, 5].map((i) => <span key={i} className={i < no ? "done" : i === no ? "cur" : ""} />)}</div>
                        <span className="muted-2 mono" style={{ fontSize: "11px" }}>{no}/5</span>
                      </div>
                    </td>
                    <td><span className={`pill ${projPillClass(project)}`}><span className="dot" />{projStatusLabel(project)}</span></td>
                    <td className="muted-2">{projDate(project)}</td>
                    <td>
                      <div className="row-action">
                        <a href="#" onClick={(event) => { event.preventDefault(); event.stopPropagation(); openPipeline(project.id); }} title="继续"><svg width="14" height="14" viewBox="0 0 16 16"><path d="M5 4l6 4-6 4z" fill="currentColor" /></svg></a>
                        <span className="row-more" onClick={(event) => event.stopPropagation()}>
                          <svg width="14" height="14" viewBox="0 0 16 16"><circle cx="3" cy="8" r="1.2" fill="currentColor" /><circle cx="8" cy="8" r="1.2" fill="currentColor" /><circle cx="13" cy="8" r="1.2" fill="currentColor" /></svg>
                          <div className="row-more-tip"><button className="mi" type="button" onClick={(event) => { event.stopPropagation(); setDeleteTarget(project); }}><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M3 6h18" /><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2" /><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6" /></svg>删除项目</button></div>
                        </span>
                      </div>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      ) : (
        <div className="proj-grid">{filtered.map((project) => {
          const cover = projCover(project.name);
          return (
            <article className="proj-card" key={project.id} onClick={() => openPipeline(project.id)}>
              <div className={`placeholder card-thumb${cover ? " has-mock-media" : ""}`} style={cover ? projMock(cover) : undefined}><span className="ph-frame">9:16</span></div>
              <div className="card-body">
                <div className="card-name">{project.name}</div>
                <div className="card-sub">{productTitle(project.product)}</div>
                <div className="card-foot"><span className={`pill ${projPillClass(project)}`}><span className="dot" />{projStatusLabel(project)}</span><span className="card-time">{projDate(project)}</span></div>
              </div>
            </article>
          );
        })}</div>
      )}
      {filtered.length === 0 && <EmptyPanel title="当前筛选下没有项目" action="新建视频项目" onAction={() => navigate("projectWizard")} />}
      <ConfirmModal open={Boolean(deleteTarget)} title="确认删除项目" detail={`即将删除 ${deleteTarget?.name || ""}。`} confirmText="删除" onCancel={() => setDeleteTarget(null)} onConfirm={confirmDelete} />
    </section>
  );
}
