#!/bin/bash
# 白板讲解视频工作台 CLI —— 每期内容在 config.json dirs.projects，中间产物与成片在 dirs.build
#   wb new "<标题>"            新建一期：<projects>/<今天日期> <标题>/scenes.js（从模板复制）
#   wb list                    列出所有期
#   wb scenes <期>             生成 Excalidraw 场景 + script.json + 旁白稿.md
#   wb stills <期>             导出每个 beat 的静帧到 <后台>/<期>/work/frames/（检查排版）
#   wb image <期> name="英文描述" [最多4个]   codex 出白板贴纸 → <期>/assets/<name>.png
#   wb logo <期> name="Commons 文件名.svg|搜索词" [--vs=a,b]   真实 Logo → <期>/assets/<name>.png（--search="词" 只列候选）
#   wb tts <期> [scene]        火山克隆音配旁白
#   wb render <期> [scene]     渲染 → <后台>/<期>/work/out/master.mp4
#   wb mix <期> [gain]         混 BGM → <后台>/<期>/outputs/final.mp4
#   wb cover <期>              出封面 → <期>/封面-4x3.png、封面-3x4.png（scenes.js 里 build 第三参 cover）
#   wb build <期>              scenes + tts + render + mix + cover 一条龙，出片后自动 clean
#   wb clean <期>              清中间产物：work/frames 静帧、work/out 里已不在场景表的旧分段（分段与 master 保留）
#   wb open <期>               在 Finder 里打开期目录与后台目录
#   <期> 可以是目录名、标题或日期的任意子串，如 wb build 薄肌
set -eo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"
PROJECTS=$(node -p "require('./lib/paths.cjs').PROJECTS_DIR")
resolve() { node -p "require('./lib/paths.cjs').resolveProject(process.argv[1])" "$1"; }
finalOf() { node -p "require('./lib/paths.cjs').projectPaths(process.argv[1]).final" "$1"; }
studioOf() { node -p "require('./lib/paths.cjs').projectPaths(process.argv[1]).studio" "$1"; }

cmd="$1"; shift || true
case "$cmd" in
  new)
    [ -z "$1" ] && { echo "用法: wb new \"<标题>\""; exit 1; }
    case "$1" in */*|*$'\n'*|*$'\r'*) echo "Title must be one line without slashes"; exit 1 ;; esac
    dir="$PROJECTS/$(date +%Y-%m-%d) $1"
    [ -e "$dir" ] && { echo "已存在 $dir"; exit 1; }
    mkdir -p "$dir"
    node - "$1" "$dir" "$ROOT" <<'NODE'
const fs = require('node:fs');
const path = require('node:path');
const [title, dir, root] = process.argv.slice(2);
for (const name of ['scenes.js', '发布.md']) {
  const template = fs.readFileSync(path.join(root, 'templates', name), 'utf8');
  const content = template.replaceAll("'__WB_ROOT__/lib/scene-dsl'", JSON.stringify(path.join(root, 'lib/scene-dsl'))).replaceAll('__TITLE__', () => title);
  fs.writeFileSync(path.join(dir, name), content);
}
NODE
    echo "已创建：$dir/scenes.js 与 发布.md"
    echo "下一步：编辑 scenes.js → wb stills \"$1\""
    ;;
  list) node -p "require('./lib/paths.cjs').listProjects().join('\n')" ;;
  scenes) P=$(resolve "$1"); node "$P/scenes.js" ;;
  stills) P=$(resolve "$1"); node "$P/scenes.js" >/dev/null; shift; node lib/render.js "$P" --stills "$@"; echo "静帧在 $(studioOf "$P")/work/frames/" ;;
  image) P=$(resolve "$1"); shift; node lib/gen-image.mjs "$P" "$@" ;;
  logo)
    if [[ "$1" == --search=* ]]; then node lib/fetch-logo.mjs _ "$1"; exit; fi
    P=$(resolve "$1"); shift; node lib/fetch-logo.mjs "$P" "$@" ;;
  tts) P=$(resolve "$1"); shift; node lib/tts-volc.mjs "$P" "$@" 2>&1 | grep -vE "^\s+at " ;;
  render) P=$(resolve "$1"); shift; node lib/render.js "$P" "$@" ;;
  clean) P=$(resolve "$1"); node lib/render.js "$P" --clean ;;
  cover) P=$(resolve "$1"); node "$P/scenes.js" >/dev/null; node lib/render.js "$P" --cover ;;
  mix) P=$(resolve "$1"); shift; node lib/mix-bgm.mjs "$P" "$@"; node "$P/scenes.js" >/dev/null ;;
  build)
    P=$(resolve "$1")
    node "$P/scenes.js"
    node lib/tts-volc.mjs "$P" 2>&1 | grep -vE "^\s+at "
    node lib/render.js "$P"
    node lib/mix-bgm.mjs "$P"
    node "$P/scenes.js" >/dev/null   # 刷新旁白稿里的时长与成片链接
    if [ -f "$P/scenes/cover.json" ]; then node lib/render.js "$P" --cover; else echo "（没定义封面，跳过；见 wb cover）"; fi
    node lib/render.js "$P" --clean
    echo "成片：$(finalOf "$P")"
    ;;
  open) P=$(resolve "$1"); open "$P"; S=$(studioOf "$P"); [ -d "$S" ] && open "$S" ;;
  *) sed -n '2,16p' "$ROOT/bin/wb" ;;
esac
