#!/usr/bin/env python3
"""
auto_rename_improved.py 的测试套件
包含功能测试、边界条件测试、错误处理测试等
"""

import os
import sys
import json
import tempfile
import shutil
from pathlib import Path
from datetime import datetime
from unittest.mock import patch, MagicMock

# 导入要测试的模块
sys.path.insert(0, str(Path(__file__).parent))
from auto_rename_improved import WukongRenamerImproved

class TestWukongRenamer:
    def __init__(self):
        self.test_results = {
            'timestamp': datetime.now().isoformat(),
            'tests_passed': 0,
            'tests_failed': 0,
            'tests_skipped': 0,
            'test_details': []
        }

    def log_test_result(self, test_name: str, passed: bool, message: str = "", details: dict = None):
        """记录测试结果"""
        result = {
            'test_name': test_name,
            'passed': passed,
            'message': message,
            'details': details or {},
            'timestamp': datetime.now().isoformat()
        }

        self.test_results['test_details'].append(result)

        if passed:
            self.test_results['tests_passed'] += 1
            print(f"✅ {test_name}: {message}")
        else:
            self.test_results['tests_failed'] += 1
            print(f"❌ {test_name}: {message}")

    def setup_test_environment(self):
        """设置测试环境"""
        # 创建临时测试目录
        self.test_dir = Path(tempfile.mkdtemp(prefix="wukong_test_"))
        self.original_dir = self.test_dir / "original_file"
        self.original_dir.mkdir(parents=True)

        # 创建测试文件
        self.test_files = [
            "wukong-1.0.0-linux-amd64.deb",
            "wukong-1.0.0-mac-arm64.dmg",
            "wukong-1.0.0-mac-x64.dmg",
            "wukong-1.0.0-win-x64-setup.exe",
            "wukong-1.0.0-win-x86-setup.exe",
            "wukong-1.0.0-linux-x64.tar.gz",
            "wukong-v2.1.0-beta-mac-arm64.dmg",
            "wukong-latest-win-x64.msi",
            "wukong-0.9.5.blockmap",  # 应该被跳过
            "unknown-file.txt",  # 应该被跳过
            "wukong-1.2.3.4-linux-x64.tar.gz"  # 四段版本号
        ]

        # 创建空文件作为测试文件
        for filename in self.test_files:
            (self.original_dir / filename).write_text("test content")

        print(f"📁 测试环境设置完成: {self.test_dir}")
        return self.test_dir

    def cleanup_test_environment(self):
        """清理测试环境"""
        try:
            shutil.rmtree(self.test_dir)
            print(f"🧹 测试环境已清理: {self.test_dir}")
        except Exception as e:
            print(f"⚠️ 清理测试环境失败: {e}")

    def test_version_extraction(self):
        """测试版本号提取功能"""
        print("\n🧪 测试版本号提取功能")

        test_cases = [
            ("wukong-1.0.0-linux-amd64.deb", "1.0.0"),
            ("wukong-v2.1.0-beta-mac-arm64.dmg", "2.1.0-beta"),
            ("wukong-1.2.3.4-linux-x64.tar.gz", "1.2.3.4"),
            ("wukong-0.9.5.dmg", "0.9.5"),
            ("wukong-latest-win-x64.msi", None),
            ("unknown-file.txt", None),
        ]

        # 创建临时测试实例
        renamer = object.__new__(WukongRenamerImproved)
        renamer.debug = False

        for filename, expected_version in test_cases:
            actual_version = renamer.extract_version(filename)
            passed = actual_version == expected_version
            message = f"期望: {expected_version}, 实际: {actual_version}"
            self.log_test_result(f"版本提取_{filename}", passed, message)

    def test_platform_detection(self):
        """测试平台和架构检测功能"""
        print("\n🧪 测试平台和架构检测功能")

        test_cases = [
            ("wukong-1.0.0-linux-amd64.deb", ("linux", "amd64")),
            ("wukong-1.0.0-mac-arm64.dmg", ("mac", "arm64")),
            ("wukong-1.0.0-mac-x64.dmg", ("mac", "x64")),
            ("wukong-1.0.0-win-x64-setup.exe", ("win", "x64")),
            ("wukong-1.0.0-win-x86-setup.exe", ("win", "x86")),
            ("wukong-1.0.0-win-x64.msi", ("win", "x64")),
            ("unknown-file.txt", (None, None)),
        ]

        renamer = object.__new__(WukongRenamerImproved)
        renamer.debug = False
        # 设置必要的属性
        renamer.platform_mapping = {
            'linux-amd64.deb': ('linux', 'amd64'),
            'mac-arm64.dmg': ('mac', 'arm64'),
            'mac-x64.dmg': ('mac', 'x64'),
            'mac-intel.dmg': ('mac', 'intel'),
            'x64-setup.exe': ('win', 'x64'),
            'ia32-setup.exe': ('win', 'x86'),
            'win-x64.exe': ('win', 'x64'),
            'win-x86.exe': ('win', 'x86'),
            'win-x64.msi': ('win', 'x64'),
            'win-x86.msi': ('win', 'x86'),
        }

        for filename, expected in test_cases:
            actual = renamer.get_file_platform(filename)
            passed = actual == expected
            message = f"文件: {filename}, 期望: {expected}, 实际: {actual}"
            self.log_test_result(f"平台检测_{filename}", passed, message)

    def test_file_processing(self):
        """测试文件处理功能"""
        print("\n🧪 测试文件处理功能")

        # 使用实际的测试目录
        test_dir = self.setup_test_environment()

        try:
            # 修改脚本的路径配置以使用测试目录
            with patch('auto_rename_improved.WukongRenamerImproved.__init__') as mock_init:
                def init_side_effect(self, debug=False):
                    self.base_path = test_dir
                    self.original_folder = test_dir / "original_file"
                    self.update_file = test_dir / "update.txt"
                    self.log_file = test_dir / "rename_log.json"
                    self.debug = debug
                    self.platform_mapping = {
                        'linux-amd64.deb': ('linux', 'amd64'),
                        'mac-arm64.dmg': ('mac', 'arm64'),
                        'mac-x64.dmg': ('mac', 'x64'),
                        'win-x64-setup.exe': ('win', 'x64'),
                        'win-x86-setup.exe': ('win', 'x86'),
                        'linux-x64.tar.gz': ('linux', 'x64'),
                    }
                    self.processing_results = {
                        'timestamp': datetime.now().isoformat(),
                        'processed_files': [],
                        'skipped_files': [],
                        'errors': [],
                        'latest_version': None,
                        'success_count': 0,
                        'skip_count': 0
                    }

                mock_init.side_effect = init_side_effect

                # 执行文件处理
                renamer = WukongRenamerImproved()
                success = renamer.process_files()

                # 验证处理结果
                self.log_test_result("文件处理总体", success, "文件处理是否成功")

                # 验证文件是否正确移动和重命名
                expected_files = [
                    ("linux", "wukong-1.0.0"),
                    ("mac", "arm64"),
                    ("mac", "x64"),
                    ("win", "x64"),
                    ("win", "x86")
                ]

                for platform, name_part in expected_files:
                    if platform == "mac":
                        target_dir = test_dir / "mac" / name_part
                    else:
                        target_dir = test_dir / platform
                        if platform == "win":
                            target_dir = target_dir / name_part

                    if target_dir.exists():
                        files = list(target_dir.glob("wukong-*.d*"))
                        passed = len(files) > 0
                        message = f"目录: {target_dir}, 文件数: {len(files)}"
                        self.log_test_result(f"文件移动_{platform}_{name_part}", passed, message)

                # 验证版本文件更新
                update_file = test_dir / "update.txt"
                if update_file.exists():
                    with open(update_file, 'r', encoding='utf-8') as f:
                        version_info = json.load(f)
                    version_exists = 'version' in version_info
                    self.log_test_result("版本文件更新", version_exists, f"版本信息: {version_info}")

                # 验证日志文件生成
                log_file = test_dir / "rename_log.json"
                log_exists = log_file.exists()
                self.log_test_result("日志文件生成", log_exists, f"日志文件: {log_file}")

        finally:
            self.cleanup_test_environment()

    def test_error_handling(self):
        """测试错误处理机制"""
        print("\n🧪 测试错误处理机制")

        # 测试不存在的源目录
        with patch('auto_rename_improved.WukongRenamerImproved.__init__') as mock_init:
            def init_side_effect(self, debug=False):
                self.base_path = Path("/nonexistent/path")
                self.original_folder = self.base_path / "original_file"
                self.update_file = self.base_path / "update.txt"
                self.log_file = self.base_path / "rename_log.json"
                self.debug = debug
                self.processing_results = {
                    'timestamp': datetime.now().isoformat(),
                    'processed_files': [],
                    'skipped_files': [],
                    'errors': [],
                    'latest_version': None,
                    'success_count': 0,
                    'skip_count': 0
                }

            mock_init.side_effect = init_side_effect

            renamer = WukongRenamerImproved()
            success = renamer.process_files()

            # 应该返回失败
            self.log_test_result("不存在的源目录", not success, "应该正确处理不存在的目录错误")

    def test_edge_cases(self):
        """测试边界条件"""
        print("\n🧪 测试边界条件")

        # 测试空目录
        empty_dir = Path(tempfile.mkdtemp(prefix="wukong_empty_test_"))
        original_dir = empty_dir / "original_file"
        original_dir.mkdir()

        try:
            with patch('auto_rename_improved.WukongRenamerImproved.__init__') as mock_init:
                def init_side_effect(self, debug=False):
                    self.base_path = empty_dir
                    self.original_folder = empty_dir / "original_file"
                    self.update_file = empty_dir / "update.txt"
                    self.log_file = empty_dir / "rename_log.json"
                    self.debug = debug
                    self.processing_results = {
                        'timestamp': datetime.now().isoformat(),
                        'processed_files': [],
                        'skipped_files': [],
                        'errors': [],
                        'latest_version': None,
                        'success_count': 0,
                        'skip_count': 0
                    }

                mock_init.side_effect = init_side_effect

                renamer = WukongRenamerImproved()
                success = renamer.process_files()

                # 空目录应该返回失败但不抛出异常
                self.log_test_result("空目录处理", not success, "应该正确处理空目录")

        finally:
            shutil.rmtree(empty_dir)

    def run_all_tests(self):
        """运行所有测试"""
        print("🚀 开始运行测试套件")
        print("=" * 50)

        try:
            self.test_version_extraction()
            self.test_platform_detection()
            self.test_file_processing()
            self.test_error_handling()
            self.test_edge_cases()

        except Exception as e:
            print(f"❌ 测试执行过程中发生异常: {e}")
            self.test_results['tests_failed'] += 1

        self.print_test_summary()
        return self.test_results

    def print_test_summary(self):
        """打印测试总结"""
        print("\n" + "=" * 50)
        print("📊 测试总结:")
        print(f"  ✅ 通过: {self.test_results['tests_passed']}")
        print(f"  ❌ 失败: {self.test_results['tests_failed']}")
        print(f"  ⏭️ 跳过: {self.test_results['tests_skipped']}")

        total = self.test_results['tests_passed'] + self.test_results['tests_failed']
        if total > 0:
            pass_rate = (self.test_results['tests_passed'] / total) * 100
            print(f"  📈 通过率: {pass_rate:.1f}%")

        # 保存测试结果
        results_file = Path("test_results.json")
        try:
            with open(results_file, 'w', encoding='utf-8') as f:
                json.dump(self.test_results, f, indent=2, ensure_ascii=False)
            print(f"  📄 详细结果已保存到: {results_file}")
        except Exception as e:
            print(f"  ⚠️ 保存测试结果失败: {e}")

def main():
    """主函数"""
    tester = TestWukongRenamer()
    results = tester.run_all_tests()

    # 根据测试结果返回退出码
    return 0 if results['tests_failed'] == 0 else 1

if __name__ == "__main__":
    exit(main())