"""主流水线：视频 → ASR → 字幕 + 图文直播 + manifest。

用法：
  python3 pipeline.py <视频路径> [--model small] [--device cpu] [--language zh]

输出到 outputs/<视频名>/ ：
  transcript.json   带词级时间戳的完整转写（segment 数据模型）
  subtitles.srt / subtitles.vtt
  posts.json        图文直播条目（post 数据模型）
  manifest.json     播放器所需的文件清单
  <视频名>.<ext>    源视频软链接/副本（供播放器回放）
"""
import argparse
import json
import os
import shutil
import sys

import config
from asr import transcribe
from posts import build_posts
from subtitles import to_srt, to_vtt


def link_or_copy(src, dst):
    """优先软链接省空间，跨设备失败时退化为复制；目标已存在时幂等处理。"""
    src_abs = os.path.abspath(src)
    if os.path.exists(dst):
        # 已是同一文件的软链接/副本 → 无需处理
        if os.path.realpath(dst) == os.path.realpath(src_abs):
            return "already-linked"
        # 否则清除旧目标（软链接或旧副本），重新建立
        os.remove(dst)
    try:
        os.symlink(src_abs, dst)
        return "symlink"
    except OSError:
        shutil.copy2(src_abs, dst)
        return "copy"


def main(argv=None):
    ap = argparse.ArgumentParser(description="会议录播转写 MVP 流水线")
    ap.add_argument("video", help="视频/音频文件路径")
    ap.add_argument("--model", default=config.MODEL_SIZE)
    ap.add_argument("--device", default=config.DEVICE)
    ap.add_argument("--compute-type", default=config.COMPUTE_TYPE)
    ap.add_argument("--language", default=config.LANGUAGE)
    ap.add_argument("--beam-size", type=int, default=config.BEAM_SIZE)
    ap.add_argument("--out", default=config.OUTPUT_DIR)
    ap.add_argument("--post-max-gap", type=float, default=config.POST_MAX_GAP)
    ap.add_argument("--post-max-duration", type=float, default=config.POST_MAX_DURATION)
    args = ap.parse_args(argv)

    if not os.path.exists(args.video):
        print(f"错误：文件不存在 {args.video}")
        sys.exit(1)

    name = os.path.splitext(os.path.basename(args.video))[0]
    ext = os.path.splitext(args.video)[1]
    outdir = os.path.join(args.out, name)
    os.makedirs(outdir, exist_ok=True)

    # [1/4] 转写
    print(f"[1/4] 转写中：{args.video}  (model={args.model}, device={args.device}, "
          f"compute_type={args.compute_type}, language={args.language})")
    # "auto"/"None"/"" → 自动检测语言；否则显式指定
    lang = None if args.language in ("auto", "None", "") else args.language
    segments, info = transcribe(
        args.video,
        model_size=args.model,
        device=args.device,
        compute_type=args.compute_type,
        language=lang,
        beam_size=args.beam_size,
        vad_min_silence_ms=config.VAD_MIN_SILENCE_MS,
    )
    print(f"[2/4] 完成：{len(segments)} 个片段，检测语言={info['language']}，"
          f"音频时长={info['duration']:.1f}s")

    for i, seg in enumerate(segments, 1):
        seg["id"] = f"seg_{i:04d}"

    # transcript.json
    transcript = {
        "meta": {
            "source": os.path.basename(args.video),
            "model": args.model,
            "device": args.device,
            "compute_type": args.compute_type,
            **info,
        },
        "segments": segments,
    }
    with open(os.path.join(outdir, "transcript.json"), "w", encoding="utf-8") as f:
        json.dump(transcript, f, ensure_ascii=False, indent=2)

    # [3/4] 字幕
    print("[3/4] 生成字幕 SRT/VTT ...")
    with open(os.path.join(outdir, "subtitles.srt"), "w", encoding="utf-8") as f:
        f.write(to_srt(segments))
    with open(os.path.join(outdir, "subtitles.vtt"), "w", encoding="utf-8") as f:
        f.write(to_vtt(segments))

    # [4/4] 图文直播
    print("[4/4] 生成图文直播条目 ...")
    posts = build_posts(segments, args.post_max_gap, args.post_max_duration)
    with open(os.path.join(outdir, "posts.json"), "w", encoding="utf-8") as f:
        json.dump({"posts": posts}, f, ensure_ascii=False, indent=2)

    # 源视频链接进输出目录，供播放器回放
    video_dst = os.path.join(outdir, name + ext)
    how = link_or_copy(args.video, video_dst)

    manifest = {
        "video": name + ext,
        "subtitles_vtt": "subtitles.vtt",
        "posts": "posts.json",
        "transcript": "transcript.json",
        "video_link_mode": how,
    }
    with open(os.path.join(outdir, "manifest.json"), "w", encoding="utf-8") as f:
        json.dump(manifest, f, ensure_ascii=False, indent=2)

    print(f"\n完成！输出目录：{outdir}")
    print(f"  片段数：{len(segments)}  图文直播条目：{len(posts)}")
    print(f"  播放器：http://localhost:8080/player/?dir={args.out}/{name}")


if __name__ == "__main__":
    main()
