#!/usr/bin/env python3
"""
Script to SRT with Timing · 剧本到 SRT 时间轴生成器
==========================​=====================
用剧本台词和配音时长生成正式 SRT，别手写测试时间轴。

功能：
  1. 读取剧本台词（JSON/MD/TXT）
  2. 读取配音文件（获取每条台词的实际时长）
  3. 自动计算时间轴（考虑角色对话间隔）
  4. 生成标准 SRT 字幕文件
  5. 支持多角色、旁白、音效标注

依赖：
  pip install pysrt

输入格式：
  # 剧本 JSON 格式（推荐）
  [
    {"id": 1, "character": "苏白", "text": "付费才能修仙？", "audio_file": "./audio/subai_001.wav"},
    {"id": 2, "character": "旁白", "text": "天道宗门口", "audio_file": "./audio/narrator_001.wav"}
  ]

  # 剧本 MD 格式（兼容）
  ## E1-SHOT01
  **苏白**：付费才能修仙？（audio: subai_001.wav）
  **旁白**：天道宗门口（audio: narrator_001.wav）

输出 SRT 格式：
  1
  00:00:01,000 --> 00:00:03,500
  付费才能修仙？

  2
  00:00:03,800 --> 00:00:05,200
  天道宗门口

用法：
  # 从剧本 JSON + 配音文件生成 SRT
  python script-to-srt-with-timing.py --script script.json --output subtitles.srt

  # 指定配音目录（自动匹配 audio_file）
  python script-to-srt-with-timing.py --script script.json --audio-dir ./audio/ --output subtitles.srt

  # 从 MD 剧本生成
  python script-to-srt-with-timing.py --script script.md --output subtitles.srt

  # 自定义对话间隔（秒）
  python script-to-srt-with-timing.py --script script.json --gap 0.3 --output subtitles.srt

路径：
  video-ai-system/engines/subtitle-pipeline/srt-tools/script-to-srt-with-timing.py
"""

import argparse
import json
import os
import sys
import re
from pathlib import Path

try:
    import pysrt
except ImportError:
    print("[ERROR] 缺少依赖：pysrt")
    print("请先安装：pip install pysrt")
    sys.exit(1)


def parse_script_json(script_path: str) -> list:
    """
    解析剧本 JSON 文件
    
    :param script_path: 剧本 JSON 文件路径
    :return: 台词列表 [{"id", "character", "text", "audio_file", "start", "end"}]
    """
    with open(script_path, "r", encoding="utf-8") as f:
        script = json.load(f)
    
    print(f"[INFO] 读取剧本 JSON：{len(script)} 条台词")
    return script


def parse_script_md(script_path: str) -> list:
    """
    解析剧本 MD 文件（兼容格式）
    
    :param script_path: 剧本 MD 文件路径
    :return: 台词列表
    """
    with open(script_path, "r", encoding="utf-8") as f:
        lines = f.readlines()
    
    script = []
    current_id = 0
    
    for line in lines:
        # 匹配：**角色**：台词（audio: file.wav）
        match = re.match(r"\*\*(.+?)\*\*[：:]\s*(.+?)\s*\(audio:\s*(.+?)\)", line.strip())
        if match:
            character = match.group(1).strip()
            text = match.group(2).strip()
            audio_file = match.group(3).strip()
            
            script.append({
                "id": current_id + 1,
                "character": character,
                "text": text,
                "audio_file": audio_file
            })
            current_id += 1
    
    print(f"[INFO] 读取剧本 MD：{len(script)} 条台词")
    return script


def get_audio_duration(audio_path: str) -> float:
    """
    获取音频文件时长（秒）
    
    :param audio_path: 音频文件路径
    :return: 时长（秒）
    """
    try:
        import ffmpeg
        probe = ffmpeg.probe(audio_path)
        duration = float(probe['format']['duration'])
        return duration
    except ImportError:
        # 如果没有 ffmpeg-python，使用 ffprobe 命令行
        try:
            import subprocess
            cmd = [
                "ffprobe", "-v", "quiet", "-print_format", "json",
                "-show_format", "-show_streams", audio_path
            ]
            result = subprocess.run(cmd, capture_output=True, text=True, check=True)
            probe = json.loads(result.stdout)
            duration = float(probe['format']['duration'])
            return duration
        except Exception as e:
            print(f"[WARN] 无法获取音频时长：{audio_path} ({e})")
            # 估算：中文普通话约 4-6 字/秒
            return 2.0  # 默认 2 秒
    except Exception as e:
        print(f"[WARN] 无法获取音频时长：{audio_path} ({e})")
        return 2.0


def calculate_timings(script: list, audio_dir: str = None, gap: float = 0.2) -> list:
    """
    计算时间轴
    
    :param script: 台词列表
    :param audio_dir: 配音文件目录（如果 audio_file 是相对路径）
    :param gap: 对话间隔（秒）
    :return: 带时间轴的台词列表
    """
    current_time = 0.0
    
    for item in script:
        # 获取配音文件时长
        audio_file = item.get("audio_file")
        
        if audio_file and os.path.isfile(audio_file):
            duration = get_audio_duration(audio_file)
        elif audio_file and audio_dir:
            audio_path = os.path.join(audio_dir, audio_file)
            if os.path.isfile(audio_path):
                duration = get_audio_duration(audio_path)
            else:
                # 估算时长
                text = item.get("text", "")
                duration = len(text) / 5.0  # 假设 5 字/秒
        else:
            # 没有配音文件，估算时长
            text = item.get("text", "")
            duration = len(text) / 5.0  # 假设 5 字/秒
        
        # 设置开始和结束时间
        item["start"] = current_time
        item["end"] = current_time + duration
        
        # 更新当前时间（加上间隔）
        current_time = item["end"] + gap
    
    print(f"[INFO] 时间轴计算完成：总时长 {current_time:.2f} 秒")
    return script


def generate_srt(script: list, output_path: str):
    """
    生成 SRT 字幕文件
    
    :param script: 带时间轴的台词列表
    :param output_path: 输出 SRT 文件路径
    """
    # 创建 pysrt SubRipFile
    subs = pysrt.SubRipFile()
    
    for item in script:
        # 创建字幕项
        sub = pysrt.SubRipItem()
        sub.index = item["id"]
        sub.text = item["text"]
        
        # 设置时间
        start_seconds = item["start"]
        end_seconds = item["end"]
        
        sub.start.hours = int(start_seconds // 3600)
        sub.start.minutes = int((start_seconds % 3600) // 60)
        sub.start.seconds = int(start_seconds % 60)
        sub.start.milliseconds = int((start_seconds % 1) * 1000)
        
        sub.end.hours = int(end_seconds // 3600)
        sub.end.minutes = int((end_seconds % 3600) // 60)
        sub.end.seconds = int(end_seconds % 60)
        sub.end.milliseconds = int((end_seconds % 1) * 1000)
        
        subs.append(sub)
    
    # 保存 SRT 文件
    os.makedirs(os.path.dirname(os.path.abspath(output_path)), exist_ok=True)
    subs.save(output_path, encoding="utf-8")
    
    print(f"[OK] SRT 字幕文件已生成：{output_path}")
    print(f"[INFO] 共 {len(script)} 条字幕")


def main():
    parser = argparse.ArgumentParser(
        description="Script to SRT with Timing · 剧本到 SRT 时间轴生成器",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
示例：
  python script-to-srt-with-timing.py --script script.json --output subtitles.srt
  python script-to-srt-with-timing.py --script script.md --audio-dir ./audio/ --output subtitles.srt
  python script-to-srt-with-timing.py --script script.json --gap 0.3 --output subtitles.srt
"""
    )
    parser.add_argument("--script", required=True, help="剧本文件路径（JSON 或 MD 格式）")
    parser.add_argument("--audio-dir", help="配音文件目录（如果 audio_file 是相对路径）")
    parser.add_argument("--output", required=True, help="输出 SRT 文件路径")
    parser.add_argument("--gap", type=float, default=0.2, help="对话间隔（秒，默认 0.2）")
    
    args = parser.parse_args()
    
    # 检查剧本文件是否存在
    if not os.path.isfile(args.script):
        print(f"[ERROR] 剧本文件不存在：{args.script}")
        sys.exit(1)
    
    # 解析剧本
    if args.script.lower().endswith(".json"):
        script = parse_script_json(args.script)
    elif args.script.lower().endswith(".md"):
        script = parse_script_md(args.script)
    else:
        print(f"[ERROR] 不支持的剧本格式：{args.script}")
        print("支持格式：.json, .md")
        sys.exit(1)
    
    if not script:
        print("[ERROR] 剧本为空，请检查格式")
        sys.exit(1)
    
    # 计算时间轴
    script = calculate_timings(script, args.audio_dir, args.gap)
    
    # 生成 SRT 文件
    generate_srt(script, args.output)
    
    print("\n[OK] 处理完成")


if __name__ == "__main__":
    main()
