#!/usr/bin/env python3
"""
场景检测器
"""

from abc import ABC, abstractmethod
from typing import List

from python_core.utils.logger import logger

class SceneDetector(ABC):
    """场景检测器接口"""

    @abstractmethod
    def detect_scenes(self, file_path: str, threshold: float = 30.0) -> List[float]:
        """检测场景变化点"""
        pass

class PySceneDetectSceneDetector(SceneDetector):
    """使用PySceneDetect进行场景检测"""

    def detect_scenes(self, file_path: str, threshold: float = 30.0) -> List[float]:
        """使用PySceneDetect检测场景变化点"""
        try:
            from scenedetect import VideoManager, SceneManager
            from scenedetect.detectors import ContentDetector
        except ImportError:
            raise Exception("PySceneDetect not available")

        try:
            video_manager = VideoManager([file_path])
            scene_manager = SceneManager()
            scene_manager.add_detector(ContentDetector(threshold=threshold))

            video_manager.start()
            scene_manager.detect_scenes(frame_source=video_manager)

            scene_list = scene_manager.get_scene_list()

            scene_changes = [0.0]
            for scene in scene_list:
                start_time = scene[0].get_seconds()
                end_time = scene[1].get_seconds()

                if start_time > 0 and start_time not in scene_changes:
                    scene_changes.append(start_time)

                if end_time not in scene_changes:
                    scene_changes.append(end_time)

            # 如果没有检测到场景变化，添加视频结束时间
            if len(scene_changes) == 1:  # 只有开始时间0.0
                try:
                    duration_obj = video_manager.get_duration()
                    if hasattr(duration_obj, 'get_seconds'):
                        video_duration = duration_obj.get_seconds()
                    elif isinstance(duration_obj, (tuple, list)) and len(duration_obj) >= 2:
                        frames, fps = duration_obj[0], duration_obj[1]
                        video_duration = frames / fps if fps > 0 else 0
                    elif isinstance(duration_obj, (int, float)):
                        video_duration = float(duration_obj)
                    else:
                        video_duration = self._get_video_duration_fallback(file_path)

                    if video_duration > 0:
                        scene_changes.append(video_duration)
                        logger.info(f"No scenes detected, using full video duration: {video_duration:.2f}s")
                except Exception as e:
                    logger.warning(f"Failed to get video duration: {e}")
                    video_duration = self._get_video_duration_fallback(file_path)
                    if video_duration > 0:
                        scene_changes.append(video_duration)

            scene_changes = sorted(list(set(scene_changes)))
            video_manager.release()

            logger.info(f"PySceneDetect found {len(scene_changes)-1} scene changes")
            return scene_changes

        except Exception as e:
            logger.error(f"PySceneDetect failed: {e}")
            raise

    def _get_video_duration_fallback(self, file_path: str) -> float:
        """获取视频时长的回退方案"""
        try:
            import cv2
            cap = cv2.VideoCapture(file_path)
            fps = cap.get(cv2.CAP_PROP_FPS)
            frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
            cap.release()

            if fps > 0:
                return frame_count / fps
            return 0.0
        except Exception:
            return 0.0

class OpenCVSceneDetector(SceneDetector):
    """使用OpenCV进行场景检测"""

    def detect_scenes(self, file_path: str, threshold: float = 30.0) -> List[float]:
        """使用OpenCV检测场景变化点"""
        try:
            import cv2
            import numpy as np
        except ImportError:
            raise Exception("OpenCV not available")

        try:
            cap = cv2.VideoCapture(file_path)
            fps = cap.get(cv2.CAP_PROP_FPS)

            if fps <= 0:
                cap.release()
                logger.warning(f"Invalid fps ({fps}) for video {file_path}")
                return [0.0]

            scene_changes = [0.0]
            prev_frame = None
            frame_count = 0
            frame_skip = max(1, int(fps / 2))

            while True:
                ret, frame = cap.read()
                if not ret:
                    break

                if frame_count % frame_skip == 0:
                    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
                    gray = cv2.resize(gray, (320, 240))

                    if prev_frame is not None:
                        diff = cv2.absdiff(prev_frame, gray)
                        mean_diff = np.mean(diff)

                        if mean_diff > threshold:
                            timestamp = frame_count / fps
                            if not scene_changes or timestamp - scene_changes[-1] > 1.0:
                                scene_changes.append(timestamp)

                    prev_frame = gray

                frame_count += 1

            cap.release()

            duration = frame_count / fps if fps > 0 else 0
            if duration > 0 and (not scene_changes or duration - scene_changes[-1] > 0.5):
                scene_changes.append(duration)

            logger.info(f"OpenCV detected {len(scene_changes)-1} scene changes")
            return scene_changes

        except Exception as e:
            logger.error(f"Failed to detect scene changes with OpenCV: {e}")
            raise

def create_scene_detector() -> SceneDetector:
    """创建场景检测器"""
    # 优先使用PySceneDetect，回退到OpenCV
    try:
        return PySceneDetectSceneDetector()
    except Exception:
        try:
            return OpenCVSceneDetector()
        except Exception:
            raise Exception("No scene detector available")
