// ———— Mock data ————
const MECHS = ["身份落差", "传承赋能", "情感共鸣", "悬念递进", "反差冲突", "认知颠覆", "群体归属", "代际传承", "弱者逆袭"];
const MECH_COLORS = {
  "身份落差": "accent", "传承赋能": "purple", "情感共鸣": "warning",
  "悬念递进": "info", "反差冲突": "danger", "认知颠覆": "success",
  "群体归属": "neutral", "代际传承": "purple", "弱者逆袭": "danger"
};
const TYPES = ["剧情", "反转", "知识", "猎奇", "情绪", "对比"];
const STRUCTURES = ["三段式", "五段式", "悬念结构", "反转结尾"];
const PLATFORMS = [
  { id: "yt", label: "YT", name: "YouTube", cls: "platform-yt" },
  { id: "tt", label: "TT", name: "TikTok",  cls: "platform-tt" },
  { id: "bl", label: "BL", name: "B站",     cls: "platform-bl" },
];

const CHANNEL_NAMES = [
  "晚风故事集", "十点剪辑工坊", "老陈说创作", "野生剧本家",
  "周更剪刀手", "纪录片之眼", "镜头下的生活", "分钟观察",
  "阿杜做内容", "小林讲剧本", "老K工作室", "三分钟剧作"
];
const VIDEO_TITLES = [
  "离家十五年的父亲回来了，家里没人认识他",
  "凌晨三点的急诊科，医生说了这样一句话",
  "奶奶偷偷藏在樟木箱里的旧信，揭开了半个世纪的秘密",
  "外卖小哥接了一单，送到的地方让他愣住了",
  "她在婚礼前一天，收到了一个陌生快递",
  "我花三年拍了一条没人看的短片，结果转机出现在第1037天",
  "同一道菜，在三家店吃下来，才明白差别在哪里",
  "关掉所有字幕，你还能看懂短视频吗",
  "教练说这个动作我练了12年，今天才做对",
  "从月薪3000到30万，这一年我做对了什么",
  "他把爷爷留下的老怀表修好了，里面有张字条",
  "地铁上陌生人塞给我一张纸，回家我哭了一整夜",
  "开了8年的面馆要关门，最后一天来了意想不到的客人",
  "装修完发现少了一堵墙，才知道是我爸留给我的",
  "演了300个龙套，今天我终于有了第一句台词",
  "从北京回到县城，我爸说了一句让我破防的话",
  "一条没被刷到的爆款，我扒了它三天三夜",
  "摆摊的大爷每天只卖20份，理由让全网沉默",
  "被裁员那天，同事说的话比HR还扎心",
  "她妈妈把所有朋友圈都删了，只留下这一条"
];

function seeded(i) { return (x) => ((Math.sin(i * 9999 + x * 31) + 1) * 500000) | 0; }

const MOCK_VIDEOS = Array.from({ length: 54 }, (_, i) => {
  const r = seeded(i);
  const plat = PLATFORMS[i % 3];
  const mechCount = 2 + (r(1) % 3);
  const mechs = Array.from({ length: mechCount }, (_, j) => MECHS[(r(j+2) % MECHS.length)]).filter((m,j,a)=>a.indexOf(m)===j);
  const score = 55 + (r(5) % 40);
  const views = 10000 + (r(6) % 9000000);
  const duration = 30 + (r(7) % 540);
  const days = r(8) % 200;
  const publishedDate = new Date(Date.now() - days * 86400000);
  return {
    id: `v${(1000 + i).toString(36)}`,
    title: VIDEO_TITLES[i % VIDEO_TITLES.length],
    channel: CHANNEL_NAMES[i % CHANNEL_NAMES.length],
    platform: plat,
    mechanisms: mechs,
    type: TYPES[i % TYPES.length],
    structure: STRUCTURES[i % STRUCTURES.length],
    score,
    views,
    duration,
    publishedAt: publishedDate,
    thumbHue: 220 + (i * 13) % 120,
    radar: {
      "故事逻辑": 60 + (r(9) % 35),
      "画面质量": 55 + (r(10) % 40),
      "角色一致性": 50 + (r(11) % 45),
      "节奏匹配": 58 + (r(12) % 38),
    },
    emotionPath: ["好奇", "认同", "冲击", "释怀", "共鸣"].slice(0, 3 + (r(13) % 3)),
    conflicts: [
      { label: "表层信息矛盾", level: 30 + (r(14)%40) },
      { label: "人物关系错位", level: 40 + (r(15)%40) },
      { label: "价值观正面冲撞", level: 50 + (r(16)%45) },
      { label: "身份真相揭露", level: 60 + (r(17)%35) },
    ].slice(0, 3 + (r(18)%2)),
    transferable: [
      "可复用冷开场：3秒内抛出身份反差",
      "情绪锚点可换：将家庭线换为师徒线",
      "结尾留白可替换为开放式提问",
    ],
    metricsHistory: Array.from({ length: 24 }, (_, h) => ({
      t: new Date(Date.now() - (24 - h) * 3600 * 1000 / 2),
      v: Math.max(0, (views * (0.2 + h / 28)) * (0.85 + ((r(h+20) % 30) / 100))) | 0
    })),
  };
});

const MOCK_JOBS = [
  { id: "j-e7a2", title: "开了8年的面馆要关门，最后一天来了意想不到的客人", platform: PLATFORMS[0], status: "完成", progress: 100, createdAt: "2 分钟前" },
  { id: "j-bb91", title: "地铁上陌生人塞给我一张纸，回家我哭了一整夜", platform: PLATFORMS[1], status: "分析中", progress: 72, createdAt: "刚刚" },
  { id: "j-4410", title: "关键词:「传承赋能 三段式」 · 自动采集 20 条", platform: PLATFORMS[2], status: "采集中", progress: 38, createdAt: "刚刚", isKeyword: true },
  { id: "j-9c3f", title: "他把爷爷留下的老怀表修好了，里面有张字条", platform: PLATFORMS[0], status: "完成", progress: 100, createdAt: "12 分钟前" },
  { id: "j-2d7e", title: "https://www.tiktok.com/@user/video/730...", platform: PLATFORMS[1], status: "失败", progress: 45, createdAt: "25 分钟前", error: "HTTP 403 · 视频不可访问或已被作者删除（TikTokDownloader timeout 30s）" },
  { id: "j-150a", title: "从北京回到县城，我爸说了一句让我破防的话", platform: PLATFORMS[0], status: "完成", progress: 100, createdAt: "1 小时前" },
  { id: "j-88c2", title: "凌晨三点的急诊科，医生说了这样一句话", platform: PLATFORMS[2], status: "待采集", progress: 0, createdAt: "1 小时前" },
];

const HERMES_INSIGHT = `根据知识库中 127 条语义相关视频的分析，**「传承赋能 × 三段式 × 情感共鸣」** 这一组合在近 90 天的可复刻爆款池中出现频率为 **18.3%**，高于整体基准 2.4 倍。

核心规律如下：
- **冷开场 3 秒必须建立身份反差**（例如：普通外壳 / 不普通的物件、空间、关系）。命中该规律的样本 CTR 中位数 **11.2%**，未命中仅 4.6%。
- **第二幕转折锚点偏好「信物 / 手写字 / 遗留物品」**，共出现在 73% 的高分样本中；相比纯对话转折，观看完成率高出 **14 个百分点**。
- **结尾处理**：开放式提问或留白 > 明确说教。高分样本中 81% 采用前者，完播后互动率为后者的 1.9 倍。

建议优先复刻 \`v1003\`、\`v100n\`、\`v100z\` 三条样本——它们在雷达图四个维度上的方差都小于 0.12，代表该方向上执行稳定性最高。`;

window.MECHS = MECHS;
window.MECH_COLORS = MECH_COLORS;
window.TYPES = TYPES;
window.STRUCTURES = STRUCTURES;
window.PLATFORMS = PLATFORMS;
window.MOCK_VIDEOS = MOCK_VIDEOS;
window.MOCK_JOBS = MOCK_JOBS;
window.HERMES_INSIGHT = HERMES_INSIGHT;

function formatViews(n) {
  if (n >= 10000) return (n / 10000).toFixed(n >= 100000 ? 0 : 1) + "w";
  return n.toString();
}
function formatDuration(sec) {
  const m = Math.floor(sec / 60), s = sec % 60;
  return `${m}:${s.toString().padStart(2,"0")}`;
}
function formatDate(d) {
  if (!d) return "—";
  const dd = typeof d === "string" ? new Date(d) : d;
  if (isNaN(dd.getTime())) return "—";
  return `${dd.getFullYear()}-${(dd.getMonth()+1).toString().padStart(2,"0")}-${dd.getDate().toString().padStart(2,"0")}`;
}
function formatDateTime(d) {
  const dd = typeof d === "string" ? new Date(d) : d;
  return `${dd.getMonth()+1}/${dd.getDate()} ${dd.getHours().toString().padStart(2,"0")}:${dd.getMinutes().toString().padStart(2,"0")}:${dd.getSeconds().toString().padStart(2,"0")}`;
}
window.formatViews = formatViews;
window.formatDuration = formatDuration;
window.formatDate = formatDate;
window.formatDateTime = formatDateTime;
