#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
字幕封面生成器 - 后端处理逻辑
"""

import os
import sys
import json
import time
import tempfile
import subprocess
from pathlib import Path
from typing import Dict, Any, Optional, List, Tuple
import logging

# ⚠️ 修复模块路径：确保 Python 能找到 modules 和其他本地模块
# 将脚本所在目录（python 目录）添加到 sys.path
script_dir = os.path.dirname(os.path.abspath(__file__))
if script_dir not in sys.path:
    sys.path.insert(0, script_dir)
    print(f"[PATH] Added to sys.path: {script_dir}", file=sys.stderr)

try:
    import cv2
    import numpy as np
    from PIL import Image, ImageDraw, ImageFont, ImageFilter
    import jieba
    # import moviepy.editor  # 暂时注释掉，需要时再启用
except ImportError as e:
    print(f"缺少必要的依赖库: {e}")
    print("请安装以下库:")
    print("pip install opencv-python pillow jieba")
    sys.exit(1)

try:
    from modules.font_manager import get_font_manager
    FONT_MANAGER_AVAILABLE = True
    print("[PATH] font_manager loaded successfully", file=sys.stderr)
except ImportError as e:
    FONT_MANAGER_AVAILABLE = False
    print(f"[PATH] Warning: font_manager module not available: {e}", file=sys.stderr)

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)

class VideoSubtitleCoverGenerator:
    """字幕封面生成器"""

    def __init__(self, config: Dict[str, Any]):
        self.config = config
        self.logger = logging.getLogger(__name__)

        # 字幕样式预设
        self.subtitle_presets = {
            "classic": {
                "fontFamily": "Arial",
                "fontSize": 24,
                "fontColor": "#FFFFFF",
                "backgroundColor": "#000000",
                "backgroundColorOpacity": 0.7,
                "position": "bottom"
            },
            "modern": {
                "fontFamily": "NotoSerifCJK-VF",
                "fontSize": 28,
                "fontColor": "#FFD700",
                "backgroundColor": "#1a1a1a",
                "backgroundColorOpacity": 0.8,
                "position": "bottom"
            },
            "minimal": {
                "fontFamily": "NotoSerifCJK-VF",
                "fontSize": 22,
                "fontColor": "#FFFFFF",
                "backgroundColor": "",
                "backgroundColorOpacity": 0,
                "position": "center"
            },
            "bold": {
                "fontFamily": "NotoSerifCJK-VF",
                "fontSize": 30,
                "fontColor": "#FF0000",
                "backgroundColor": "#FFFF00",
                "backgroundColorOpacity": 0.9,
                "position": "top"
            }
        }

        # 封面样式预设
        self.cover_presets = {
            "big-text": {
                "timePointType": "random",
                "customTimePoint": 10,
                "textOverlay": "",
                "fontSize": 72,
                "fontColor": "white",
                "position": "center",
                "backgroundColor": True,
                "backgroundOpacity": 60,
                "maxWidth": 90,
                "effectType": "blur",
                "quality": 95
            },
            "search-card": {
                "timePointType": "middle",
                "customTimePoint": 50,
                "textOverlay": "",
                "fontSize": 48,
                "fontColor": "white",
                "position": "bottom-left",
                "backgroundColor": True,
                "backgroundOpacity": 80,
                "maxWidth": 70,
                "effectType": "none",
                "quality": 95
            },
            "cut-angle": {
                "timePointType": "start",
                "customTimePoint": 5,
                "textOverlay": "",
                "fontSize": 56,
                "fontColor": "yellow",
                "position": "bottom-right",
                "backgroundColor": False,
                "backgroundOpacity": 0,
                "maxWidth": 75,
                "effectType": "gradient",
                "quality": 95
            },
            "blur-person": {
                "timePointType": "random",
                "customTimePoint": 15,
                "textOverlay": "",
                "fontSize": 64,
                "fontColor": "white",
                "position": "bottom-center",
                "backgroundColor": True,
                "backgroundOpacity": 50,
                "maxWidth": 85,
                "effectType": "blur-person",
                "quality": 95
            }
        }

    def get_subtitle_preset(self, preset_id: str) -> Dict[str, Any]:
        """获取字幕预设样式"""
        return self.subtitle_presets.get(preset_id, self.subtitle_presets["classic"])

    def get_cover_preset(self, preset_id: str) -> Dict[str, Any]:
        """获取封面预设样式"""
        return self.cover_presets.get(preset_id, self.cover_presets["big-text"])

    def extract_frame_at_time(self, video_path: str, time_seconds: float) -> Optional[np.ndarray]:
        """从视频中提取指定时间的帧"""
        try:
            cap = cv2.VideoCapture(video_path)
            if not cap.isOpened():
                self.logger.error(f"无法打开视频文件: {video_path}")
                return None

            # 设置时间位置
            cap.set(cv2.CAP_PROP_POS_MSEC, time_seconds * 1000)

            ret, frame = cap.read()
            cap.release()

            if ret:
                return frame
            else:
                self.logger.warning(f"无法读取视频帧: {time_seconds}s")
                return None

        except Exception as e:
            self.logger.error(f"提取视频帧失败: {e}")
            return None

    def get_video_duration(self, video_path: str) -> float:
        """获取视频时长"""
        try:
            cap = cv2.VideoCapture(video_path)
            if not cap.isOpened():
                return 0

            fps = cap.get(cv2.CAP_PROP_FPS)
            frame_count = cap.get(cv2.CAP_PROP_FRAME_COUNT)
            duration = frame_count / fps if fps > 0 else 0

            cap.release()
            return duration

        except Exception as e:
            self.logger.error(f"获取视频时长失败: {e}")
            return 0

    def get_optimal_frame_time(self, video_path: str, time_point_type: str, custom_time: float) -> float:
        """获取最佳帧时间点"""
        duration = self.get_video_duration(video_path)

        if time_point_type == "start":
            return min(custom_time, duration * 0.1)  # 前10%
        elif time_point_type == "middle":
            return duration * (custom_time / 100)  # 百分比位置
        elif time_point_type == "end":
            return max(duration - custom_time, duration * 0.9)  # 后10%
        elif time_point_type == "random":
            import random
            # 随机选择前60%的位置，避免片尾
            return random.uniform(0, duration * 0.6)
        else:
            return min(custom_time, duration * 0.5)  # 默认中间位置

    def apply_cover_effect(self, image: Image.Image, effect_type: str) -> Image.Image:
        """应用封面特效"""
        if effect_type == "blur":
            # 高斯模糊背景
            return image.filter(ImageFilter.GaussianBlur(radius=5))
        elif effect_type == "blur-person":
            # 模拟人物虚化效果 (简单的中心区域保持清晰)
            width, height = image.size
            # 创建遮罩
            mask = Image.new('L', (width, height), 128)
            # 中心区域清晰
            center_x, center_y = width // 2, height // 2
            radius = min(width, height) // 4
            for x in range(width):
                for y in range(height):
                    dist = ((x - center_x) ** 2 + (y - center_y) ** 2) ** 0.5
                    if dist < radius:
                        mask.putpixel((x, y), 255)  # 清晰
                    else:
                        mask.putpixel((x, y), 64)   # 模糊

            blurred = image.filter(ImageFilter.GaussianBlur(radius=3))
            return Image.composite(image, blurred, mask)
        elif effect_type == "gradient":
            # 渐变效果
            width, height = image.size
            gradient = Image.new('L', (width, height), 0)
            draw = ImageDraw.Draw(gradient)

            # 创建对角线渐变
            for x in range(width):
                for y in range(height):
                    # 计算渐变值
                    factor = (x + y) / (width + height)
                    value = int(255 * (0.3 + 0.7 * factor))  # 30%-100% 不透明度
                    gradient.putpixel((x, y), value)

            # 创建半透明图层
            overlay = Image.new('RGBA', (width, height), (0, 0, 0, 0))
            gradient_rgba = Image.new('RGBA', (width, height), (0, 0, 0, 128))
            overlay = Image.composite(overlay, gradient_rgba, gradient)

            return Image.alpha_composite(image.convert('RGBA'), overlay).convert('RGB')
        else:
            return image

    def add_text_to_image(self, image: Image.Image, text: str, style_config: Dict[str, Any]) -> Image.Image:
        """在图片上添加文字"""
        if not text.strip():
            return image

        img = image.copy()
        draw = ImageDraw.Draw(img)
        width, height = img.size

        # 获取字体（支持自定义字体）
        font_size = style_config.get('fontSize', 48)
        font_name = style_config.get('fontName', 'NotoSerifCJK-VF')  # 从配置获取字体名称
        font_weight = style_config.get('fontWeight', 400)
        font = self._load_font_safe(font_name, font_size, font_weight)

        # 计算文字尺寸
        bbox = draw.textbbox((0, 0), text, font=font)
        text_width = bbox[2] - bbox[0]
        text_height = bbox[3] - bbox[1]

        # 限制最大宽度
        max_width_percent = style_config.get('maxWidth', 80) / 100
        max_width = int(width * max_width_percent)

        if text_width > max_width:
            # 如果文字太宽，需要调整字体大小
            scale_factor = max_width / text_width
            new_font_size = int(font_size * scale_factor)
            try:
                font = ImageFont.truetype(font_family, new_font_size)
            except:
                font = ImageFont.load_default()

            # 重新计算文字尺寸
            bbox = draw.textbbox((0, 0), text, font=font)
            text_width = bbox[2] - bbox[0]
            text_height = bbox[3] - bbox[1]

        # 计算位置
        position = style_config.get('position', 'center')
        font_color = style_config.get('fontColor', 'white')

        # 解析颜色
        if isinstance(font_color, str) and font_color.startswith('#'):
            r = int(font_color[1:3], 16)
            g = int(font_color[3:5], 16)
            b = int(font_color[5:7], 16)
            font_color = (r, g, b)
        elif font_color == 'white':
            font_color = (255, 255, 255)
        elif font_color == 'yellow':
            font_color = (255, 255, 0)
        else:
            font_color = (255, 255, 255)

        # 计算文字位置
        if position == 'center':
            x = (width - text_width) // 2
            y = (height - text_height) // 2
        elif position == 'bottom-left':
            x = 50
            y = height - text_height - 50
        elif position == 'bottom-right':
            x = width - text_width - 50
            y = height - text_height - 50
        elif position == 'bottom-center':
            x = (width - text_width) // 2
            y = height - text_height - 50
        elif position == 'top-left':
            x = 50
            y = 50
        elif position == 'top-right':
            x = width - text_width - 50
            y = 50
        elif position == 'top-center':
            x = (width - text_width) // 2
            y = 50
        else:  # 默认居中
            x = (width - text_width) // 2
            y = (height - text_height) // 2

        # 添加背景
        background_color = style_config.get('backgroundColor', True)
        background_opacity = style_config.get('backgroundOpacity', 70)

        if background_color and background_opacity > 0:
            # 创建半透明背景
            padding = 20
            bg_x1 = max(0, x - padding)
            bg_y1 = max(0, y - padding)
            bg_x2 = min(width, x + text_width + padding)
            bg_y2 = min(height, y + text_height + padding)

            # 创建半透明黑色背景
            background = Image.new('RGBA', (width, height), (0, 0, 0, 0))
            bg_draw = ImageDraw.Draw(background)

            # 计算背景颜色 (黑色半透明)
            alpha = int(255 * (background_opacity / 100))
            bg_color = (0, 0, 0, alpha)

            bg_draw.rectangle([bg_x1, bg_y1, bg_x2, bg_y2], fill=bg_color)
            img = Image.alpha_composite(img.convert('RGBA'), background).convert('RGB')

            # 重新创建draw对象
            draw = ImageDraw.Draw(img)

        # 绘制文字
        draw.text((x, y), text, font=font, fill=font_color)

        return img

    def generate_cover_with_custom_template(self, video_path: str, output_path: str, template: Dict[str, Any]) -> bool:
        """使用自定义模板生成封面"""
        try:
            # 提取视频的中间帧
            duration = self.get_video_duration(video_path)
            time_point = duration * 0.5  # 使用中间帧

            frame = self.extract_frame_at_time(video_path, time_point)
            if frame is None:
                self.logger.error("无法提取视频帧")
                return False

            # 转换为PIL图像
            image = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
            width, height = image.size

            # 1. 应用背景模糊（如果启用）
            background_config = template.get('background', {})
            if background_config.get('blurEnabled', False):
                blur_radius = background_config.get('blurRadius', 15)
                image = image.filter(ImageFilter.GaussianBlur(radius=blur_radius))

            # 2. 处理人像描边（如果启用）
            portrait_config = template.get('portrait', {})
            if portrait_config.get('strokeEnabled', False):
                # 创建绘图对象
                draw = ImageDraw.Draw(image)

                # 获取人像位置和大小（百分比转换为像素）
                pos = portrait_config.get('position', {'x': 50, 'y': 50})
                size = portrait_config.get('size', {'width': 50, 'height': 70})

                portrait_x = int(pos['x'] / 100 * width)
                portrait_y = int(pos['y'] / 100 * height)
                portrait_width = int(size['width'] / 100 * width)
                portrait_height = int(size['height'] / 100 * height)

                # 绘制描边框
                stroke_color = portrait_config.get('strokeColor', '#FFD700')
                stroke_width = portrait_config.get('strokeWidth', 3)
                stroke_type = portrait_config.get('strokeType', 'solid')

                # 计算矩形边界
                left = portrait_x - portrait_width // 2
                top = portrait_y - portrait_height // 2
                right = portrait_x + portrait_width // 2
                bottom = portrait_y + portrait_height // 2

                if stroke_type == 'dashed':
                    # 虚线描边
                    dash_pattern = portrait_config.get('strokeDashPattern', [10, 5])
                    # 简化实现：绘制虚线矩形
                    # 这里需要手动绘制虚线，PIL不直接支持
                    pass  # 简化处理，暂时使用实线

                # 绘制实线矩形
                for i in range(stroke_width):
                    draw.rectangle(
                        [left - i, top - i, right + i, bottom + i],
                        outline=stroke_color,
                        width=1
                    )

            # 3. 添加标题文字
            titles_config = template.get('titles', {})

            # 主标题
            main_title = titles_config.get('main', {})
            main_text = main_title.get('text', '')
            if main_text:
                self._draw_text_with_stroke(
                    image,
                    main_text,
                    main_title,
                    width,
                    height
                )

            # 副标题
            sub_title = titles_config.get('sub', {})
            sub_text = sub_title.get('text', '')
            if sub_text:
                self._draw_text_with_stroke(
                    image,
                    sub_text,
                    sub_title,
                    width,
                    height
                )

            # 4. 添加蒙版（如果有）
            mask_config = template.get('mask', {})
            mask_path = mask_config.get('imagePath', '')
            if mask_path and os.path.exists(mask_path):
                try:
                    mask_img = Image.open(mask_path).convert('RGBA')

                    # 获取蒙版位置和大小
                    mask_pos = mask_config.get('position', {'x': 10, 'y': 10})
                    mask_size = mask_config.get('size', {'width': 30, 'height': 20})
                    mask_opacity = mask_config.get('opacity', 0.8)

                    mask_width = int(mask_size['width'] / 100 * width)
                    mask_height = int(mask_size['height'] / 100 * height)
                    mask_x = int(mask_pos['x'] / 100 * width)
                    mask_y = int(mask_pos['y'] / 100 * height)

                    # 调整蒙版大小和透明度
                    mask_img = mask_img.resize((mask_width, mask_height), Image.Resampling.LANCZOS)
                    if mask_opacity < 1.0:
                        alpha = mask_img.split()[3]
                        alpha = alpha.point(lambda p: int(p * mask_opacity))
                        mask_img.putalpha(alpha)

                    # 将蒙版粘贴到图像上
                    image_rgba = image.convert('RGBA')
                    image_rgba.paste(mask_img, (mask_x - mask_width // 2, mask_y - mask_height // 2), mask_img)
                    image = image_rgba.convert('RGB')
                except Exception as e:
                    self.logger.warning(f"添加蒙版失败: {e}")

            # 保存图片
            image.save(output_path, 'JPEG', quality=95)
            self.logger.info(f"自定义模板封面生成成功: {output_path}")
            return True

        except Exception as e:
            self.logger.error(f"生成自定义模板封面失败: {e}")
            return False

    def _load_font_safe(self, font_name: str = None, font_size: int = 24, font_weight: int = 400) -> ImageFont.FreeTypeFont:
        """
        加载字体，支持自定义字体、ziti目录、系统字体
        优先顺序：ziti目录 -> FontManager -> 系统字体 -> 默认字体

        Args:
            font_name: 字体名称（如 "微软雅黑"、"墨趣古风体" 等）
            font_size: 字体大小
            font_weight: 字体粗细 (100-1000)

        Returns:
            字体对象
        """
        import platform

        # 1. 首先直接尝试在 ziti 目录查找字体文件
        if font_name:
            # 多个可能的 ziti 目录路径（相对和绝对）
            possible_ziti_paths = [
                os.path.join(os.getcwd(), 'ziti'),  # 当前工作目录
                os.path.join(os.path.dirname(__file__), '..', 'ziti'),  # 相对于脚本
                os.path.join(os.path.dirname(__file__), '..', '..', 'ziti'),  # 项目根目录
                'ziti',  # 相对路径
                os.path.expanduser('~/ziti'),  # 用户主目录
            ]

            # 尝试找到 ziti 目录
            for ziti_dir in possible_ziti_paths:
                if os.path.isdir(ziti_dir):
                    self.logger.info(f"Found ziti directory: {ziti_dir}")

                    # 在 ziti 目录中查找字体文件
                    for ext in ['.ttf', '.otf', '.ttc']:
                        # 直接按字体名称查找
                        font_path = os.path.join(ziti_dir, font_name + ext)
                        if os.path.exists(font_path):
                            try:
                                return ImageFont.truetype(font_path, font_size)
                            except Exception as e:
                                self.logger.warning(f"Failed to load ziti font from {font_path}: {e}")

                    # 如果没有找到，扫描目录中所有文件进行模糊匹配
                    try:
                        for file in os.listdir(ziti_dir):
                            if not file.startswith('.') and (file.endswith('.ttf') or file.endswith('.otf') or file.endswith('.ttc')):
                                file_base = os.path.splitext(file)[0]
                                # 检查是否匹配（精确或包含）
                                if file_base == font_name or font_name in file_base:
                                    font_path = os.path.join(ziti_dir, file)
                                    try:
                                        return ImageFont.truetype(font_path, font_size)
                                    except Exception as e:
                                        self.logger.warning(f"Failed to load matched font {font_path}: {e}")
                    except Exception as e:
                        self.logger.warning(f"Error scanning ziti directory: {e}")

        # 2. 如果 ziti 目录查找失败，使用 FontManager
        if font_name and FONT_MANAGER_AVAILABLE:
            try:
                font_manager = get_font_manager()
                font_path = font_manager.find_font(font_name, font_weight)

                if font_path and os.path.exists(font_path):
                    try:
                        return ImageFont.truetype(font_path, font_size)
                    except Exception as e:
                        self.logger.warning(f"Failed to load custom font from {font_path}: {e}")
            except Exception as e:
                self.logger.warning(f"Font manager error: {e}")

        # 3. 降级：根据操作系统加载默认系统字体
        system = platform.system()
        font_paths = []

        if system == 'Windows':
            font_dir = None
            font_paths = [
                os.path.join(font_dir, 'NotoSerifCJK-VF'),      # 微软雅黑
                '',    # 微软雅黑 Bold
                '',    # 黑体
                '',    # 宋体
            ]
        elif system == 'Darwin':  # macOS
            font_paths = [
                '/Library/Fonts/PingFang.ttc',
                '/System/Library/Fonts/PingFang.ttc',
            ]
        else:  # Linux
            font_paths = [
                '/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc',
            ]

        # 尝试加载每个字体
        for font_path in font_paths:
            if os.path.exists(font_path):
                try:
                    return ImageFont.truetype(font_path, font_size)
                except:
                    continue

        return ImageFont.load_default()

    def _draw_text_with_stroke(self, image: Image.Image, text: str, config: Dict[str, Any], img_width: int, img_height: int):
        """在图片上绘制带描边的文字"""
        if not text:
            return

        # 获取配置
        font_size = config.get('fontSize', 60)
        font_weight = config.get('fontWeight', 700)
        font_name = config.get('fontName', 'NotoSerifCJK-VF')  # 从配置获取字体名称
        color = config.get('color', '#FFFFFF')
        stroke_color = config.get('strokeColor', '#000000')
        stroke_width = config.get('strokeWidth', 2)
        position = config.get('position', {'x': 50, 'y': 20})

        # 加载字体（使用改进的字体加载逻辑，支持自定义字体）
        font = self._load_font_safe(font_name, font_size, font_weight)

        # 计算文字位置
        text_x = int(position['x'] / 100 * img_width)
        text_y = int(position['y'] / 100 * img_height)

        # 创建绘图对象
        draw = ImageDraw.Draw(image)

        # 绘制描边（多次绘制以模拟描边效果）
        if stroke_width > 0:
            for adj_x in range(-stroke_width, stroke_width + 1):
                for adj_y in range(-stroke_width, stroke_width + 1):
                    if adj_x != 0 or adj_y != 0:
                        draw.text(
                            (text_x + adj_x, text_y + adj_y),
                            text,
                            font=font,
                            fill=stroke_color,
                            anchor='mm'
                        )

        # 绘制主文字
        draw.text(
            (text_x, text_y),
            text,
            font=font,
            fill=color,
            anchor='mm'
        )

    def generate_cover(self, video_path: str, output_path: str, cover_config: Dict[str, Any]) -> bool:
        """生成封面图片"""
        try:
            # 获取最佳帧时间点
            time_point = self.get_optimal_frame_time(
                video_path,
                cover_config.get('timePointType', 'random'),
                cover_config.get('customTimePoint', 10)
            )

            # 提取帧
            frame = self.extract_frame_at_time(video_path, time_point)
            if frame is None:
                self.logger.error("无法提取视频帧")
                return False

            # 转换为PIL图像
            image = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))

            # 应用特效
            effect_type = cover_config.get('effectType', 'none')
            if effect_type != 'none':
                image = self.apply_cover_effect(image, effect_type)

            # 添加文字
            text_overlay = cover_config.get('textOverlay', '').strip()
            if text_overlay:
                image = self.add_text_to_image(image, text_overlay, cover_config)

            # 保存图片
            quality = cover_config.get('quality', 95)
            image.save(output_path, 'JPEG', quality=quality)

            self.logger.info(f"封面生成成功: {output_path}")
            return True

        except Exception as e:
            self.logger.error(f"生成封面失败: {e}")
            return False

    def generate_subtitle_srt(self, text: str, video_duration: float) -> str:
        """生成字幕SRT文件内容"""
        try:
            # 使用jieba分词
            words = list(jieba.cut(text.strip()))

            # 计算字幕时长分布
            total_chars = len(text)
            if total_chars == 0:
                return ""

            # 平均每个字幕显示2-3秒
            avg_duration = min(3.0, max(2.0, video_duration / max(1, total_chars / 10)))

            srt_lines = []
            current_time = 1.0  # 从1秒开始

            for i, word in enumerate(words):
                if not word.strip():
                    continue

                start_time = current_time
                end_time = min(current_time + avg_duration, video_duration - 0.5)

                # 格式化时间 (HH:MM:SS,mmm)
                def format_time(seconds):
                    hours = int(seconds // 3600)
                    minutes = int((seconds % 3600) // 60)
                    secs = int(seconds % 60)
                    ms = int((seconds % 1) * 1000)
                    return "02d"

                start_str = format_time(start_time)
                end_str = format_time(end_time)

                srt_lines.append(f"{i+1}")
                srt_lines.append(f"{start_str} --> {end_str}")
                srt_lines.append(word)
                srt_lines.append("")  # 空行

                current_time = end_time

            return "\n".join(srt_lines)

        except Exception as e:
            self.logger.error(f"生成字幕SRT失败: {e}")
            return ""

    def add_subtitle_to_video(self, video_path: str, srt_path: str, output_path: str, subtitle_config: Dict[str, Any]) -> bool:
        """为视频添加字幕 - 简化的实现"""
        try:
            # 目前先复制原视频作为输出（字幕功能可以后续完善）
            # 实际项目中可以使用 ffmpeg 或其他视频处理库
            import shutil
            shutil.copy2(video_path, output_path)

            self.logger.info(f"视频复制成功 (字幕功能待完善): {output_path}")
            return True

        except Exception as e:
            self.logger.error(f"复制视频失败: {e}")
            return False

    def parse_srt_time(self, time_str: str) -> float:
        """解析SRT时间格式"""
        try:
            # 格式: 00:00:01,000
            parts = time_str.replace(',', ':').split(':')
            if len(parts) >= 3:
                hours = int(parts[0])
                minutes = int(parts[1])
                seconds = float(parts[2])
                return hours * 3600 + minutes * 60 + seconds
        except:
            pass
        return 0.0

    def process(self, progress_callback=None) -> Dict[str, Any]:
        """主处理流程"""
        try:
            # 检查是否使用自定义模板
            if self.config.get('customTemplate', False):
                return self._process_with_custom_template(progress_callback)

            model_config = self.config.get('modelConfig', {})
            video_path = model_config.get('video', '')

            if not video_path or not os.path.exists(video_path):
                return {
                    'code': -1,
                    'msg': f'视频文件不存在: {video_path}'
                }

            # 创建输出目录
            output_dir = os.path.dirname(video_path)
            base_name = os.path.splitext(os.path.basename(video_path))[0]

            # 更新进度: 初始化
            if progress_callback:
                progress_callback(0.1, "初始化处理...")

            # 获取字幕和封面配置
            subtitle_template = model_config.get('subtitleTemplate', 'classic')
            cover_template = model_config.get('coverTemplate', 'big-text')

            subtitle_style = self.get_subtitle_preset(subtitle_template)
            cover_style = self.get_cover_preset(cover_template)

            # 如果配置中有自定义样式，覆盖预设
            if 'subtitleStyle' in model_config:
                subtitle_style.update(model_config['subtitleStyle'])
            if 'coverStyle' in model_config:
                cover_style.update(model_config['coverStyle'])

            # 更新进度: 生成字幕
            if progress_callback:
                progress_callback(0.2, "生成字幕文件...")

            # 生成字幕SRT
            video_duration = self.get_video_duration(video_path)
            reference_text = model_config.get('referenceText', '')

            srt_content = self.generate_subtitle_srt(reference_text, video_duration)

            # 保存SRT文件
            srt_path = os.path.join(output_dir, f"{base_name}_subtitles.srt")
            with open(srt_path, 'w', encoding='utf-8') as f:
                f.write(srt_content)

            # 更新进度: 生成封面
            if progress_callback:
                progress_callback(0.5, "生成视频封面...")

            # 生成封面
            cover_path = os.path.join(output_dir, f"{base_name}_cover.jpg")
            cover_success = self.generate_cover(video_path, cover_path, cover_style)

            # 更新进度: 添加字幕到视频
            if progress_callback:
                progress_callback(0.7, "为视频添加字幕...")

            # 生成带字幕的视频
            video_with_subtitle_path = os.path.join(output_dir, f"{base_name}_with_subtitles.mp4")
            subtitle_success = self.add_subtitle_to_video(video_path, srt_path, video_with_subtitle_path, subtitle_style)

            # 更新进度: 完成
            if progress_callback:
                progress_callback(1.0, "处理完成")

            result = {
                'code': 0,
                'msg': '处理成功',
                'video': video_with_subtitle_path if subtitle_success else video_path,
                'cover': cover_path if cover_success else None,
                'srtPath': srt_path
            }

            return result

        except Exception as e:
            self.logger.error(f"处理失败: {e}")
            return {
                'code': -1,
                'msg': f'处理失败: {str(e)}'
            }

    def _process_with_custom_template(self, progress_callback=None) -> Dict[str, Any]:
        """使用自定义模板处理"""
        try:
            video_path = self.config.get('videoPath', '')
            template = self.config.get('template', {})

            if not video_path or not os.path.exists(video_path):
                return {
                    'code': -1,
                    'msg': f'视频文件不存在: {video_path}'
                }

            if not template:
                return {
                    'code': -1,
                    'msg': '缺少自定义模板配置'
                }

            # 创建输出目录
            output_dir = self.config.get('outputDir', os.path.dirname(video_path))
            if not os.path.exists(output_dir):
                os.makedirs(output_dir, exist_ok=True)

            base_name = os.path.splitext(os.path.basename(video_path))[0]

            # 更新进度: 初始化
            if progress_callback:
                progress_callback(0.1, "初始化自定义模板处理...")

            # 更新进度: 生成封面
            if progress_callback:
                progress_callback(0.5, "使用自定义模板生成封面...")

            # 生成封面
            cover_path = os.path.join(output_dir, f"{base_name}_custom_cover.jpg")
            cover_success = self.generate_cover_with_custom_template(video_path, cover_path, template)

            # 更新进度: 完成
            if progress_callback:
                progress_callback(1.0, "处理完成")

            result = {
                'success': cover_success,
                'coverPath': cover_path if cover_success else None,
                'message': '自定义模板处理成功' if cover_success else '自定义模板处理失败'
            }

            return result

        except Exception as e:
            self.logger.error(f"自定义模板处理失败: {e}")
            return {
                'success': False,
                'error': str(e),
                'message': f'自定义模板处理失败: {str(e)}'
            }


def main():
    """命令行入口"""
    if len(sys.argv) < 2:
        print("用法: python video_subtitle_cover_generator.py <config.json>")
        sys.exit(1)

    config_path = sys.argv[1]

    try:
        with open(config_path, 'r', encoding='utf-8') as f:
            config = json.load(f)

        generator = VideoSubtitleCoverGenerator(config)
        result = generator.process()

        # 输出JSON结果（单行，以便Node.js解析）
        print(json.dumps(result, ensure_ascii=False))

    except Exception as e:
        print(json.dumps({
            'success': False,
            'error': str(e),
            'message': f'执行失败: {str(e)}'
        }, ensure_ascii=False))


if __name__ == "__main__":
    main()