#!/usr/bin/env python3
"""
MediaManager 测试文件
测试视频切分、场景检测、信息提取等功能
"""

import os
import sys
import unittest
import tempfile
import shutil
from pathlib import Path
from unittest.mock import Mock, patch

# 添加项目根目录到Python路径
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))

# 导入要测试的模块
from python_core.services.media_manager import (
    MediaManager,
    DependencyManager,
    VideoProcessorFactory,
    FFProbeVideoInfoExtractor,
    OpenCVVideoInfoExtractor,
    PySceneDetectSceneDetector,
    OpenCVSceneDetector,
    OpenCVThumbnailGenerator,
    MD5FileHashCalculator,
    OpenCVVideoSegmentCreator
)

class TestDependencyManager(unittest.TestCase):
    """测试依赖管理器"""
    
    def setUp(self):
        self.dependency_manager = DependencyManager()
    
    def test_dependency_initialization(self):
        """测试依赖初始化"""
        # 检查依赖管理器是否正确初始化
        self.assertIsInstance(self.dependency_manager._dependencies, dict)
        
        # 检查是否包含预期的依赖
        self.assertIn('opencv', self.dependency_manager._dependencies)
        self.assertIn('scenedetect', self.dependency_manager._dependencies)
    
    def test_opencv_availability(self):
        """测试OpenCV可用性检查"""
        opencv_available = self.dependency_manager.is_available('opencv')
        print(f"OpenCV available: {opencv_available}")
        
        if opencv_available:
            # 如果OpenCV可用，测试模块获取
            cv2 = self.dependency_manager.get_module('opencv', 'cv2')
            self.assertIsNotNone(cv2)
            
            numpy = self.dependency_manager.get_module('opencv', 'numpy')
            self.assertIsNotNone(numpy)
    
    def test_scenedetect_availability(self):
        """测试PySceneDetect可用性检查"""
        scenedetect_available = self.dependency_manager.is_available('scenedetect')
        print(f"PySceneDetect available: {scenedetect_available}")
        
        if scenedetect_available:
            # 如果PySceneDetect可用，测试模块获取
            VideoManager = self.dependency_manager.get_module('scenedetect', 'VideoManager')
            self.assertIsNotNone(VideoManager)
    
    def test_dependency_info(self):
        """测试依赖信息获取"""
        opencv_info = self.dependency_manager.get_dependency_info('opencv')
        self.assertIsInstance(opencv_info, dict)
        self.assertIn('available', opencv_info)
        
        all_deps = self.dependency_manager.get_all_dependencies()
        self.assertIsInstance(all_deps, dict)
        self.assertIn('opencv', all_deps)
        self.assertIn('scenedetect', all_deps)

class TestVideoProcessorFactory(unittest.TestCase):
    """测试视频处理器工厂"""
    
    def setUp(self):
        self.dependency_manager = DependencyManager()
        self.factory = VideoProcessorFactory(self.dependency_manager)
    
    def test_create_video_info_extractor(self):
        """测试创建视频信息提取器"""
        try:
            extractor = self.factory.create_video_info_extractor()
            self.assertIsNotNone(extractor)
            print(f"Created video info extractor: {type(extractor).__name__}")
        except Exception as e:
            self.fail(f"Failed to create video info extractor: {e}")
    
    def test_create_scene_detector(self):
        """测试创建场景检测器"""
        try:
            detector = self.factory.create_scene_detector()
            self.assertIsNotNone(detector)
            print(f"Created scene detector: {type(detector).__name__}")
        except Exception as e:
            self.fail(f"Failed to create scene detector: {e}")
    
    def test_create_thumbnail_generator(self):
        """测试创建缩略图生成器"""
        if self.dependency_manager.is_available('opencv'):
            try:
                generator = self.factory.create_thumbnail_generator()
                self.assertIsNotNone(generator)
                print(f"Created thumbnail generator: {type(generator).__name__}")
            except Exception as e:
                self.fail(f"Failed to create thumbnail generator: {e}")
        else:
            print("OpenCV not available, skipping thumbnail generator test")
    
    def test_create_hash_calculator(self):
        """测试创建哈希计算器"""
        calculator = self.factory.create_hash_calculator()
        self.assertIsNotNone(calculator)
        self.assertIsInstance(calculator, MD5FileHashCalculator)

class TestVideoInfoExtractors(unittest.TestCase):
    """测试视频信息提取器"""
    
    def setUp(self):
        # 使用assets文件夹中的测试视频
        self.test_video = project_root / "assets" / "1" / "1752031789460.mp4"
        if not self.test_video.exists():
            self.skipTest(f"Test video not found: {self.test_video}")
    
    def test_ffprobe_extractor(self):
        """测试FFProbe视频信息提取器"""
        try:
            extractor = FFProbeVideoInfoExtractor()
            info = extractor.extract_video_info(str(self.test_video))
            
            # 验证返回的信息结构
            self.assertIsInstance(info, dict)
            self.assertIn('duration', info)
            self.assertIn('width', info)
            self.assertIn('height', info)
            self.assertIn('fps', info)
            self.assertIn('file_size', info)
            
            print(f"FFProbe video info: {info}")
            
            # 验证数值合理性
            self.assertGreater(info['duration'], 0)
            self.assertGreater(info['width'], 0)
            self.assertGreater(info['height'], 0)
            self.assertGreater(info['fps'], 0)
            self.assertGreater(info['file_size'], 0)
            
        except Exception as e:
            print(f"FFProbe extractor failed (expected if ffprobe not available): {e}")
    
    def test_opencv_extractor(self):
        """测试OpenCV视频信息提取器"""
        dependency_manager = DependencyManager()
        if not dependency_manager.is_available('opencv'):
            self.skipTest("OpenCV not available")
        
        try:
            extractor = OpenCVVideoInfoExtractor(dependency_manager)
            info = extractor.extract_video_info(str(self.test_video))
            
            # 验证返回的信息结构
            self.assertIsInstance(info, dict)
            self.assertIn('duration', info)
            self.assertIn('width', info)
            self.assertIn('height', info)
            self.assertIn('fps', info)
            self.assertIn('file_size', info)
            
            print(f"OpenCV video info: {info}")
            
            # 验证数值合理性
            self.assertGreater(info['duration'], 0)
            self.assertGreater(info['width'], 0)
            self.assertGreater(info['height'], 0)
            self.assertGreater(info['fps'], 0)
            self.assertGreater(info['file_size'], 0)
            
        except Exception as e:
            self.fail(f"OpenCV extractor failed: {e}")

class TestSceneDetectors(unittest.TestCase):
    """测试场景检测器"""
    
    def setUp(self):
        # 使用assets文件夹中的测试视频
        self.test_video = project_root / "assets" / "1" / "1752031789460.mp4"
        if not self.test_video.exists():
            self.skipTest(f"Test video not found: {self.test_video}")
        
        self.dependency_manager = DependencyManager()
    
    def test_pyscenedetect_detector(self):
        """测试PySceneDetect场景检测器"""
        if not self.dependency_manager.is_available('scenedetect'):
            self.skipTest("PySceneDetect not available")
        
        try:
            detector = PySceneDetectSceneDetector(self.dependency_manager)
            scene_changes = detector.detect_scenes(str(self.test_video), threshold=30.0)
            
            # 验证返回的场景变化点
            self.assertIsInstance(scene_changes, list)
            self.assertGreater(len(scene_changes), 0)
            
            # 第一个应该是0.0
            self.assertEqual(scene_changes[0], 0.0)
            
            # 场景变化点应该是递增的
            for i in range(1, len(scene_changes)):
                self.assertGreater(scene_changes[i], scene_changes[i-1])
            
            print(f"PySceneDetect found {len(scene_changes)} scene changes: {scene_changes}")
            
        except Exception as e:
            print(f"PySceneDetect detector failed: {e}")
    
    def test_opencv_detector(self):
        """测试OpenCV场景检测器"""
        if not self.dependency_manager.is_available('opencv'):
            self.skipTest("OpenCV not available")
        
        try:
            detector = OpenCVSceneDetector(self.dependency_manager)
            scene_changes = detector.detect_scenes(str(self.test_video), threshold=30.0)
            
            # 验证返回的场景变化点
            self.assertIsInstance(scene_changes, list)
            self.assertGreater(len(scene_changes), 0)
            
            # 第一个应该是0.0
            self.assertEqual(scene_changes[0], 0.0)
            
            # 场景变化点应该是递增的
            for i in range(1, len(scene_changes)):
                self.assertGreater(scene_changes[i], scene_changes[i-1])
            
            print(f"OpenCV found {len(scene_changes)} scene changes: {scene_changes}")
            
        except Exception as e:
            self.fail(f"OpenCV detector failed: {e}")

class TestMediaManager(unittest.TestCase):
    """测试媒体管理器"""
    
    def setUp(self):
        # 创建临时目录用于测试
        self.temp_dir = tempfile.mkdtemp()
        self.test_video = project_root / "assets" / "1" / "1752031789460.mp4"
        
        if not self.test_video.exists():
            self.skipTest(f"Test video not found: {self.test_video}")
        
        # 使用临时目录创建MediaManager
        with patch('python_core.config.settings') as mock_settings:
            mock_settings.temp_dir = Path(self.temp_dir)
            self.media_manager = MediaManager()
    
    def tearDown(self):
        # 清理临时目录
        shutil.rmtree(self.temp_dir, ignore_errors=True)
    
    def test_media_manager_initialization(self):
        """测试媒体管理器初始化"""
        self.assertIsNotNone(self.media_manager)
        self.assertIsNotNone(self.media_manager.dependency_manager)
        self.assertIsNotNone(self.media_manager.factory)
    
    def test_video_info_extraction(self):
        """测试视频信息提取"""
        try:
            video_info = self.media_manager._get_video_info(str(self.test_video))
            
            self.assertIsInstance(video_info, dict)
            self.assertIn('duration', video_info)
            self.assertIn('width', video_info)
            self.assertIn('height', video_info)
            self.assertIn('fps', video_info)
            
            print(f"Video info extracted: {video_info}")
            
        except Exception as e:
            self.fail(f"Video info extraction failed: {e}")
    
    def test_scene_detection(self):
        """测试场景检测"""
        try:
            scene_changes = self.media_manager._detect_scene_changes(str(self.test_video))
            
            self.assertIsInstance(scene_changes, list)
            self.assertGreater(len(scene_changes), 0)
            
            print(f"Scene changes detected: {scene_changes}")
            
        except Exception as e:
            self.fail(f"Scene detection failed: {e}")
    
    def test_video_splitting(self):
        """测试视频切分功能"""
        try:
            # 首先检测场景变化
            scene_changes = self.media_manager._detect_scene_changes(str(self.test_video))
            
            # 如果场景变化太少，手动添加一些切分点
            if len(scene_changes) < 3:
                video_info = self.media_manager._get_video_info(str(self.test_video))
                duration = video_info.get('duration', 10.0)
                scene_changes = [0.0, duration / 2, duration]
            
            print(f"Using scene changes for splitting: {scene_changes}")
            
            # 执行视频切分
            segments = self.media_manager._split_video_by_scenes(
                str(self.test_video),
                scene_changes,
                "test_original_id",
                ["测试", "分镜"]
            )
            
            print(f"Created {len(segments)} video segments")
            
            # 验证切分结果
            self.assertIsInstance(segments, list)
            
            for i, segment in enumerate(segments):
                print(f"Segment {i}: {segment.filename}, duration: {segment.duration}s")
                
                # 验证片段文件是否存在（如果创建成功的话）
                if hasattr(segment, 'file_path') and segment.file_path:
                    segment_path = Path(segment.file_path)
                    if segment_path.exists():
                        print(f"  File exists: {segment_path}")
                        self.assertGreater(segment_path.stat().st_size, 0)
            
        except Exception as e:
            print(f"Video splitting failed (may be expected if dependencies missing): {e}")

def run_comprehensive_test():
    """运行全面的测试"""
    print("=" * 60)
    print("MediaManager 综合测试")
    print("=" * 60)
    
    # 检查测试视频
    test_videos = list((project_root / "assets").rglob("*.mp4"))
    print(f"Found {len(test_videos)} test videos:")
    for video in test_videos[:5]:  # 只显示前5个
        print(f"  - {video}")
    
    if not test_videos:
        print("❌ No test videos found in assets folder")
        return
    
    print("\n" + "=" * 60)
    print("开始测试...")
    print("=" * 60)
    
    # 运行测试套件
    loader = unittest.TestLoader()
    suite = unittest.TestSuite()
    
    # 添加测试类
    suite.addTests(loader.loadTestsFromTestCase(TestDependencyManager))
    suite.addTests(loader.loadTestsFromTestCase(TestVideoProcessorFactory))
    suite.addTests(loader.loadTestsFromTestCase(TestVideoInfoExtractors))
    suite.addTests(loader.loadTestsFromTestCase(TestSceneDetectors))
    suite.addTests(loader.loadTestsFromTestCase(TestMediaManager))
    
    # 运行测试
    runner = unittest.TextTestRunner(verbosity=2)
    result = runner.run(suite)
    
    print("\n" + "=" * 60)
    print("测试总结")
    print("=" * 60)
    print(f"运行测试: {result.testsRun}")
    print(f"失败: {len(result.failures)}")
    print(f"错误: {len(result.errors)}")
    print(f"跳过: {len(result.skipped) if hasattr(result, 'skipped') else 0}")
    
    if result.failures:
        print("\n失败的测试:")
        for test, traceback in result.failures:
            print(f"  - {test}: {traceback}")
    
    if result.errors:
        print("\n错误的测试:")
        for test, traceback in result.errors:
            print(f"  - {test}: {traceback}")
    
    return result.wasSuccessful()

if __name__ == "__main__":
    success = run_comprehensive_test()
    sys.exit(0 if success else 1)
