#!/usr/bin/env python3
"""
文件映射一致性检查工具
对比 JSON 映射记录与实际文件情况，确保映射准确无误
"""

import json
import os
from pathlib import Path
from typing import Set, Dict

# ANSI 颜色代码
GREEN = '\033[92m'
YELLOW = '\033[93m'
RED = '\033[91m'
BLUE = '\033[94m'
CYAN = '\033[96m'
RESET = '\033[0m'


class MappingValidator:
    def __init__(self, json_file: str = "plugin_mappings.json"):
        self.base_dir = Path(os.path.dirname(os.path.dirname(
            os.path.dirname(os.path.abspath(__file__)))))
        self.json_file = self.base_dir / "plugin-dev-ja" / "sync" / json_file
        self.plugin_dir = self.base_dir / "ja-jp" / "plugins"
        self.dev_dir = self.base_dir / "plugin-dev-ja"
        self.mappings = []
        self.load_mappings()

    def load_mappings(self):
        """加载映射文件"""
        try:
            with open(self.json_file, 'r', encoding='utf-8') as f:
                data = json.load(f)
                self.mappings = data.get('mappings', [])
        except FileNotFoundError:
            print(f"{RED}错误: 找不到文件 {self.json_file}{RESET}")
            self.mappings = []
        except json.JSONDecodeError:
            print(f"{RED}错误: JSON 文件格式错误{RESET}")
            self.mappings = []

    def count_mdx_files(self, directory: Path) -> int:
        """递归统计目录中的 .mdx 文件数量"""
        count = 0
        for file in directory.rglob('*.mdx'):
            count += 1
        return count

    def get_actual_file_paths(self, directory: Path) -> Set[str]:
        """获取目录中所有 .mdx 文件的相对路径"""
        files = set()
        for file in directory.rglob('*.mdx'):
            relative_path = str(file.relative_to(self.base_dir))
            files.add(relative_path)
        return files

    def calculate_mapping_stats(self) -> Dict:
        """计算映射统计"""
        total = len(self.mappings)
        plugin_only = sum(1 for m in self.mappings if m.get(
            'plugin_path') and not m.get('dev_path'))
        dev_only = sum(1 for m in self.mappings if m.get(
            'dev_path') and not m.get('plugin_path'))
        complete = sum(1 for m in self.mappings if m.get(
            'plugin_path') and m.get('dev_path'))

        # 计算预期的文件数
        expected_plugin_files = total - dev_only  # 总数 - 仅开发 = 插件文件数
        expected_dev_files = total - plugin_only  # 总数 - 仅插件 = 开发文件数

        return {
            'total_mappings': total,
            'plugin_only': plugin_only,
            'dev_only': dev_only,
            'complete_mappings': complete,
            'expected_plugin_files': expected_plugin_files,
            'expected_dev_files': expected_dev_files
        }

    def validate(self):
        """执行验证"""
        print(f"\n{CYAN}=== 插件文档映射一致性检查工具 ==={RESET}")
        print(f"{CYAN}功能：对比 JSON 映射记录与实际文件，确保映射准确无遗漏{RESET}\n")

        # 统计实际文件数
        actual_plugin_count = self.count_mdx_files(self.plugin_dir)
        actual_dev_count = self.count_mdx_files(self.dev_dir)

        # 获取映射统计
        stats = self.calculate_mapping_stats()

        # 显示映射统计
        print(f"{BLUE}【JSON 映射统计情况】{RESET}")
        print(f"  总映射记录数: {stats['total_mappings']} 条")
        print(f"  完整映射（两边都有）: {stats['complete_mappings']} 条")
        print(f"  仅插件文档: {stats['plugin_only']} 条")
        print(f"  仅开发文档: {stats['dev_only']} 条\n")

        # 显示预期vs实际
        print(f"{BLUE}【运行时文件计数情况】{RESET}")
        print("  📁 插件文件夹 (ja-jp/plugins):")
        print(f"    JSON 映射预期: {stats['expected_plugin_files']} 个文件")
        print(f"    实际扫描结果: {actual_plugin_count} 个 .mdx 文件")
        if actual_plugin_count == stats['expected_plugin_files']:
            print(f"    状态: {GREEN}✓ 完全一致{RESET}")
        else:
            diff = actual_plugin_count - stats['expected_plugin_files']
            print(f"    状态: {RED}✗ 存在差异 (实际比预期{diff:+d}){RESET}")

        print("\n  📁 开发文件夹 (plugin-dev-ja):")
        print(f"    JSON 映射预期: {stats['expected_dev_files']} 个文件")
        print(f"    实际扫描结果: {actual_dev_count} 个 .mdx 文件")
        if actual_dev_count == stats['expected_dev_files']:
            print(f"    状态: {GREEN}✓ 完全一致{RESET}")
        else:
            diff = actual_dev_count - stats['expected_dev_files']
            print(f"    状态: {RED}✗ 存在差异 (实际比预期{diff:+d}){RESET}")

        # 显示计算公式说明
        print(f"\n{BLUE}【预期文件数计算说明】{RESET}")
        print(
            f"  插件预期数 = 总映射数({stats['total_mappings']}) - 仅开发数({stats['dev_only']}) = {stats['expected_plugin_files']}")
        print(
            f"  开发预期数 = 总映射数({stats['total_mappings']}) - 仅插件数({stats['plugin_only']}) = {stats['expected_dev_files']}")

        # 如果有差异，找出具体文件
        if actual_plugin_count != stats['expected_plugin_files'] or actual_dev_count != stats['expected_dev_files']:
            self.find_discrepancies()
        else:
            print(f"\n{GREEN}✅ 检查完成：所有文件映射完全一致！{RESET}")

    def find_discrepancies(self):
        """找出映射和实际文件的差异"""
        print(f"\n{YELLOW}【差异详细分析】{RESET}\n")

        # 获取实际文件路径
        actual_plugin_files = self.get_actual_file_paths(self.plugin_dir)
        actual_dev_files = self.get_actual_file_paths(self.dev_dir)

        # 获取映射中的文件路径
        mapped_plugin_files = set(m['plugin_path']
                                  for m in self.mappings if m.get('plugin_path'))
        mapped_dev_files = set(m['dev_path']
                               for m in self.mappings if m.get('dev_path'))

        # 找出未映射的文件
        unmapped_plugin_files = actual_plugin_files - mapped_plugin_files
        unmapped_dev_files = actual_dev_files - mapped_dev_files

        # 找出映射中但不存在的文件
        nonexistent_plugin_files = mapped_plugin_files - actual_plugin_files
        nonexistent_dev_files = mapped_dev_files - actual_dev_files

        has_issues = False

        if unmapped_plugin_files:
            has_issues = True
            print(f"{RED}❗ 实际存在但 JSON 中未记录的插件文件:{RESET}")
            for file in sorted(unmapped_plugin_files):
                print(f"  - {file}")

        if unmapped_dev_files:
            has_issues = True
            print(f"\n{RED}❗ 实际存在但 JSON 中未记录的开发文件:{RESET}")
            for file in sorted(unmapped_dev_files):
                print(f"  - {file}")

        if nonexistent_plugin_files:
            has_issues = True
            print(f"\n{RED}❗ JSON 中记录但实际不存在的插件文件:{RESET}")
            for file in sorted(nonexistent_plugin_files):
                print(f"  - {file}")

        if nonexistent_dev_files:
            has_issues = True
            print(f"\n{RED}❗ JSON 中记录但实际不存在的开发文件:{RESET}")
            for file in sorted(nonexistent_dev_files):
                print(f"  - {file}")

        if has_issues:
            print(f"\n{YELLOW}💡 建议：运行 sync_mdx_to_json.py 同步文件到映射{RESET}")
        else:
            print(f"{GREEN}未发现具体文件差异，检查完成{RESET}")


def main():
    """主函数"""
    validator = MappingValidator()
    validator.validate()


if __name__ == "__main__":
    main()
