#!/usr/bin/env python3
"""
视频信息提取器
"""

import os
import json
import subprocess
from abc import ABC, abstractmethod
from typing import Dict

from .types import VideoInfo
from python_core.utils.logger import logger

class VideoInfoExtractor(ABC):
    """视频信息提取器接口"""

    @abstractmethod
    def extract_video_info(self, file_path: str) -> VideoInfo:
        """提取视频信息"""
        pass

class FFProbeVideoInfoExtractor(VideoInfoExtractor):
    """使用FFProbe提取视频信息"""

    def extract_video_info(self, file_path: str) -> VideoInfo:
        """使用ffprobe获取准确的视频信息"""
        file_size = os.path.getsize(file_path)

        try:
            cmd = [
                'ffprobe',
                '-v', 'quiet',
                '-print_format', 'json',
                '-show_format',
                '-show_streams',
                file_path
            ]

            result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)

            if result.returncode == 0:
                probe_data = json.loads(result.stdout)

                video_stream = None
                for stream in probe_data.get('streams', []):
                    if stream.get('codec_type') == 'video':
                        video_stream = stream
                        break

                if video_stream:
                    duration = float(probe_data.get('format', {}).get('duration', 0))
                    width = int(video_stream.get('width', 0))
                    height = int(video_stream.get('height', 0))

                    fps_str = video_stream.get('r_frame_rate', '0/1')
                    if '/' in fps_str:
                        num, den = fps_str.split('/')
                        fps = float(num) / float(den) if float(den) != 0 else 0
                    else:
                        fps = float(fps_str)

                    frame_count = int(duration * fps) if fps > 0 else 0

                    logger.info(f"ffprobe video info: duration={duration:.2f}s, fps={fps:.2f}, resolution={width}x{height}")

                    return VideoInfo(
                        duration=duration,
                        width=width,
                        height=height,
                        fps=fps,
                        frame_count=frame_count,
                        file_size=file_size,
                        codec=video_stream.get('codec_name', 'unknown')
                    )

        except Exception as e:
            logger.warning(f"ffprobe failed: {e}")
            raise

        raise Exception("Failed to extract video info with ffprobe")

class OpenCVVideoInfoExtractor(VideoInfoExtractor):
    """使用OpenCV提取视频信息"""

    def extract_video_info(self, file_path: str) -> VideoInfo:
        """使用OpenCV获取视频信息"""
        try:
            import cv2
        except ImportError:
            raise Exception("OpenCV not available")

        file_size = os.path.getsize(file_path)

        try:
            cap = cv2.VideoCapture(file_path)

            fps = cap.get(cv2.CAP_PROP_FPS)
            frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
            width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
            height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
            duration = frame_count / fps if fps > 0 else 0

            cap.release()

            logger.info(f"OpenCV video info: duration={duration:.2f}s, fps={fps:.2f}, resolution={width}x{height}")

            return VideoInfo(
                duration=duration,
                width=width,
                height=height,
                fps=fps,
                frame_count=frame_count,
                file_size=file_size,
                codec='unknown'
            )
        except Exception as e:
            logger.error(f"Failed to get video info with OpenCV: {e}")
            raise

def create_video_info_extractor() -> VideoInfoExtractor:
    """创建视频信息提取器"""
    # 优先使用FFProbe，回退到OpenCV
    try:
        return FFProbeVideoInfoExtractor()
    except Exception:
        try:
            return OpenCVVideoInfoExtractor()
        except Exception:
            raise Exception("No video info extractor available")
