#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import json
import os
import re
import subprocess
from typing import Any, Dict, List, Union


def extract_timestamp_from_video_path(video_path: str) -> str:
    """
    从视频文件路径中提取时间戳。
    支持:
    - vid_00-00-00-000@00-00-20-250.mp4
    - vid-00-00-00-00-00-20.mp4
    """
    filename = os.path.basename(video_path)

    match_new = re.search(
        r"vid_(\d{2})-(\d{2})-(\d{2})-(\d{3})@(\d{2})-(\d{2})-(\d{2})-(\d{3})\.mp4",
        filename,
    )
    if match_new:
        return (
            f"{match_new.group(1)}:{match_new.group(2)}:{match_new.group(3)},{match_new.group(4)}-"
            f"{match_new.group(5)}:{match_new.group(6)}:{match_new.group(7)},{match_new.group(8)}"
        )

    match_old = re.search(r"vid-(\d{2}-\d{2}-\d{2})-(\d{2}-\d{2}-\d{2})\.mp4", filename)
    if match_old:
        start_time = match_old.group(1).replace("-", ":")
        end_time = match_old.group(2).replace("-", ":")
        return f"{start_time}-{end_time}"

    return ""


def calculate_duration(timestamp: str) -> float:
    """
    计算时间戳范围持续时长（秒），支持:
    - HH:MM:SS-HH:MM:SS
    - HH:MM:SS,mmm-HH:MM:SS,mmm
    """
    try:
        start_time, end_time = timestamp.split("-")

        if "," in start_time:
            start_hms, start_ms = start_time.split(",", 1)
            start_h, start_m, start_s = map(int, start_hms.split(":"))
            start_frac = int(start_ms) / 1000.0
        else:
            start_h, start_m, start_s = map(int, start_time.split(":"))
            start_frac = 0.0

        if "," in end_time:
            end_hms, end_ms = end_time.split(",", 1)
            end_h, end_m, end_s = map(int, end_hms.split(":"))
            end_frac = int(end_ms) / 1000.0
        else:
            end_h, end_m, end_s = map(int, end_time.split(":"))
            end_frac = 0.0

        start_seconds = start_h * 3600 + start_m * 60 + start_s + start_frac
        end_seconds = end_h * 3600 + end_m * 60 + end_s + end_frac
        return round(end_seconds - start_seconds, 3)
    except Exception:
        return 0.0


def get_audio_duration(audio_path: str) -> float:
    """用 ffprobe 获取音频真实时长（秒）。"""
    if not audio_path or not os.path.exists(audio_path):
        return 0.0
    try:
        cmd = [
            "ffprobe",
            "-v",
            "error",
            "-show_entries",
            "format=duration",
            "-of",
            "default=noprint_wrappers=1:nokey=1",
            audio_path,
        ]
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
        text = (result.stdout or "").strip()
        return round(float(text), 3) if text else 0.0
    except Exception:
        return 0.0


def _format_seconds_to_hms_ms(total_seconds: float) -> str:
    total_ms = int(round(max(0.0, total_seconds) * 1000))
    h = total_ms // 3600000
    m = (total_ms % 3600000) // 60000
    s = (total_ms % 60000) // 1000
    ms = total_ms % 1000
    return f"{h:02d}:{m:02d}:{s:02d},{ms:03d}"


def update_script_timestamps(
    script_list: List[Dict[str, Any]],
    video_result: Dict[Union[str, int], str],
    audio_result: Dict[Union[str, int], str] = None,
    subtitle_result: Dict[Union[str, int], str] = None,
    calculate_edited_timerange: bool = True,
    video_clip_json_path: str = "",
) -> List[Dict[str, Any]]:
    """
    更新脚本中音频/字幕/视频路径与时长。
    关键规则:
    - `duration` 优先使用音频真实时长（ffprobe）
    - 无音频时回退到 sourceTimeRange 推导时长
    """
    updated_script: List[Dict[str, Any]] = []

    id_timestamp_mapping: Dict[Union[str, int], Dict[str, str]] = {}
    for key, video_path in video_result.items():
        new_timestamp = extract_timestamp_from_video_path(video_path)
        if new_timestamp:
            id_timestamp_mapping[key] = {
                "new_timestamp": new_timestamp,
                "video_path": video_path,
            }

    accumulated_duration = 0.0

    for item in script_list:
        item_copy = item.copy()
        item_id = item_copy.get("_id")
        orig_timestamp = item_copy.get("timestamp", "")

        item_copy["audio"] = ""
        item_copy["subtitle"] = ""
        item_copy["video"] = ""

        if audio_result:
            if item_id and item_id in audio_result:
                item_copy["audio"] = audio_result[item_id]
            elif orig_timestamp in audio_result:
                item_copy["audio"] = audio_result[orig_timestamp]

        if subtitle_result:
            if item_id and item_id in subtitle_result:
                item_copy["subtitle"] = subtitle_result[item_id]
            elif orig_timestamp in subtitle_result:
                item_copy["subtitle"] = subtitle_result[orig_timestamp]

        if item_id and item_id in video_result:
            item_copy["video"] = video_result[item_id]
        elif orig_timestamp in video_result:
            item_copy["video"] = video_result[orig_timestamp]

        current_duration = 0.0
        if item_id and item_id in id_timestamp_mapping:
            item_copy["sourceTimeRange"] = id_timestamp_mapping[item_id]["new_timestamp"]
            current_duration = calculate_duration(item_copy["sourceTimeRange"])
        elif orig_timestamp in id_timestamp_mapping:
            item_copy["sourceTimeRange"] = id_timestamp_mapping[orig_timestamp]["new_timestamp"]
            current_duration = calculate_duration(item_copy["sourceTimeRange"])
        elif orig_timestamp:
            item_copy["sourceTimeRange"] = orig_timestamp
            current_duration = calculate_duration(orig_timestamp)

        # duration 优先使用真实音频时长
        audio_duration = get_audio_duration(item_copy.get("audio", ""))
        if audio_duration > 0:
            current_duration = audio_duration
        item_copy["duration"] = round(float(current_duration or 0), 3)

        if calculate_edited_timerange and current_duration > 0:
            start_time_seconds = accumulated_duration
            end_time_seconds = accumulated_duration + current_duration
            item_copy["editedTimeRange"] = (
                f"{_format_seconds_to_hms_ms(start_time_seconds)}-"
                f"{_format_seconds_to_hms_ms(end_time_seconds)}"
            )
            accumulated_duration = end_time_seconds

        updated_script.append(item_copy)

    if video_clip_json_path:
        if os.path.exists(video_clip_json_path):
            os.remove(video_clip_json_path)
        with open(video_clip_json_path, "w", encoding="utf-8") as file:
            json.dump(updated_script, file, indent=4, ensure_ascii=False)

    return updated_script
