#!/usr/bin/env python3
"""
EG 打包分析工具
用于分析项目结构和打包配置的完整性
"""

import os
import sys
from pathlib import Path
from typing import List, Set, Tuple

# 项目根目录
PROJECT_ROOT = Path(__file__).parent.parent.absolute()

# 当前的打包配置 (从 setup.py 同步)
DATA_DIRECTORIES = [
    # 配置和资源
    "config",
    "icons",
    "Resources",
    "tex",
    "templates",
    
    # 核心模块
    "core",
    "gui",
    "project",
    "scene",
    "scripts",
    "ssbo_component",
    "tools",
    "TransformGizmo",
    "ui",
    
    # 引擎和扩展
    "RenderPipelineFile",
    "vr_actions",
    
    # 项目模板
    "new",
]

# 排除的模式
EXCLUDE_PATTERNS = [
    "__pycache__",
    "*.pyc",
    "*.pyo",
    "*.pyd",
    ".git",
    ".gitignore",
    ".idea",
    ".vscode",
    "*.egg-info",
    "*.egg",
    "dist",
    "build",
    "*.spec",
]

# 已知的开发/构建目录 (不应该打包)
DEV_DIRECTORIES = [
    ".git",
    ".idea",
    ".vscode",
    "build",
    "build_scripts",
    "dist",
    "test_project",  # 示例项目，可选
    "__pycache__",
]

# 已知的文档文件 (可选打包)
DOC_FILES = [
    "README.md",
    "LICENSE.txt",
    "CHANGELOG.md",
    "AGENTS.md",
]


def get_directory_size(path: Path) -> Tuple[int, int]:
    """计算目录大小和文件数量"""
    total_size = 0
    file_count = 0
    
    if not path.exists():
        return 0, 0
    
    for item in path.rglob("*"):
        if item.is_file():
            # 检查是否应该排除
            should_exclude = False
            for pattern in EXCLUDE_PATTERNS:
                if pattern.startswith("*"):
                    if item.name.endswith(pattern[1:]):
                        should_exclude = True
                        break
                elif pattern in str(item.relative_to(path)):
                    should_exclude = True
                    break
            
            if not should_exclude:
                total_size += item.stat().st_size
                file_count += 1
    
    return total_size, file_count


def format_size(size_bytes: int) -> str:
    """格式化文件大小"""
    for unit in ['B', 'KB', 'MB', 'GB']:
        if size_bytes < 1024:
            return f"{size_bytes:.2f} {unit}"
        size_bytes /= 1024
    return f"{size_bytes:.2f} TB"


def analyze_project_structure():
    """分析项目结构"""
    print("=" * 70)
    print("EG 项目打包分析")
    print("=" * 70)
    print()
    
    # 获取所有目录
    all_dirs = [d for d in PROJECT_ROOT.iterdir() if d.is_dir()]
    all_dir_names = {d.name for d in all_dirs}
    
    # 分类
    packaged_dirs = []
    dev_dirs = []
    missing_dirs = []
    unknown_dirs = []
    
    for d in all_dirs:
        name = d.name
        if name in DATA_DIRECTORIES:
            packaged_dirs.append(d)
        elif name in DEV_DIRECTORIES:
            dev_dirs.append(d)
        elif name.startswith(".") or name in ["new", "test_project"]:
            # 特殊目录
            if name not in DATA_DIRECTORIES:
                missing_dirs.append(d)
        else:
            unknown_dirs.append(d)
    
    # 1. 已配置的打包目录
    print("📦 已配置的打包目录:")
    print("-" * 70)
    total_size = 0
    total_files = 0
    
    for d in sorted(packaged_dirs, key=lambda x: x.name):
        size, count = get_directory_size(d)
        total_size += size
        total_files += count
        status = "✓" if d.exists() else "✗ 不存在"
        print(f"  {status:12} {d.name:25} {format_size(size):>12} ({count} 文件)")
    
    print("-" * 70)
    print(f"  {'总计':12} {'':25} {format_size(total_size):>12} ({total_files} 文件)")
    print()
    
    # 2. 开发目录 (正确排除)
    if dev_dirs:
        print("🔧 开发/构建目录 (正确排除):")
        print("-" * 70)
        for d in sorted(dev_dirs, key=lambda x: x.name):
            size, count = get_directory_size(d)
            print(f"  {'✓ 排除':12} {d.name:25} {format_size(size):>12}")
        print()
    
    # 3. 未配置的目录 (需要检查)
    if unknown_dirs:
        print("⚠️  未配置的目录 (请检查是否需要打包):")
        print("-" * 70)
        for d in sorted(unknown_dirs, key=lambda x: x.name):
            size, count = get_directory_size(d)
            print(f"  {'? 待确认':12} {d.name:25} {format_size(size):>12} ({count} 文件)")
            # 列出部分文件帮助判断
            files = list(d.iterdir())[:5]
            for f in files:
                file_type = "📁" if f.is_dir() else "📄"
                print(f"               {file_type} {f.name}")
            if len(list(d.iterdir())) > 5:
                print(f"               ... 等 {len(list(d.iterdir())) - 5} 个文件")
        print()
    
    # 4. 检查配置中但目录不存在的
    config_only = set(DATA_DIRECTORIES) - all_dir_names
    if config_only:
        print("⚠️  配置中有但目录不存在:")
        print("-" * 70)
        for name in config_only:
            print(f"  ✗ 不存在     {name}")
        print()
    
    # 5. 关键文件检查
    print("🔑 关键文件检查:")
    print("-" * 70)
    
    critical_files = {
        "Start_Run.py": "入口脚本",
        "main.py": "主程序",
        "imgui.ini": "ImGui配置",
        "icons/app.ico": "Windows图标",
        "icons/app.png": "Linux图标",
    }
    
    for file, desc in critical_files.items():
        path = PROJECT_ROOT / file
        exists = "✓" if path.exists() else "✗"
        print(f"  {exists:3} {file:25} ({desc})")
    print()
    
    # 6. 建议
    print("💡 建议:")
    print("-" * 70)
    
    suggestions = []
    
    if unknown_dirs:
        suggestions.append(f"有 {len(unknown_dirs)} 个未配置目录，请检查是否需要打包")
    
    if config_only:
        suggestions.append(f"配置中有 {len(config_only)} 个目录不存在，请更新配置")
    
    # 检查图标
    if not (PROJECT_ROOT / "icons/app.ico").exists():
        suggestions.append("缺少 Windows 图标: icons/app.ico")
    if not (PROJECT_ROOT / "icons/app.png").exists():
        suggestions.append("缺少 Linux 图标: icons/app.png")
    
    # 检查大小
    if total_size > 500 * 1024 * 1024:
        suggestions.append(f"打包内容较大 ({format_size(total_size)})，考虑优化")
    
    if not suggestions:
        print("  ✓ 一切正常！")
    else:
        for s in suggestions:
            print(f"  • {s}")
    print()
    
    # 7. 预估输出
    print("📊 预估输出:")
    print("-" * 70)
    
    # Nuitka 编译后大约增加 20-50MB 开销
    estimated_exe_size = total_size + 50 * 1024 * 1024
    print(f"  数据文件:        {format_size(total_size)}")
    print(f"  编译开销(预估):  ~50 MB")
    print(f"  总计(预估):      {format_size(estimated_exe_size)}")
    print(f"  压缩后(预估):    {format_size(estimated_exe_size * 0.6)}")  # 假设 60% 压缩率
    print()
    
    # 返回是否有问题
    has_issues = bool(unknown_dirs or config_only or not suggestions)
    return has_issues


def generate_updated_config():
    """生成更新后的配置代码"""
    print("=" * 70)
    print("建议的配置更新")
    print("=" * 70)
    print()
    
    # 获取所有实际存在的目录
    all_dirs = {d.name for d in PROJECT_ROOT.iterdir() if d.is_dir()}
    
    # 自动分类
    auto_include = []
    auto_exclude = []
    
    for name in sorted(all_dirs):
        if name in DEV_DIRECTORIES:
            auto_exclude.append(name)
        elif name.startswith("."):
            auto_exclude.append(name)
        else:
            auto_include.append(name)
    
    print("# 自动生成的配置建议:")
    print()
    print("DATA_DIRECTORIES = [")
    for name in auto_include:
        comment = ""
        if name == "project":
            comment = "  # 项目管理模块"
        elif name == "new":
            comment = "  # 默认项目模板"
        elif name == "test_project":
            comment = "  # 示例项目 (可选)"
        print(f'    "{name}",{comment}')
    print("]")
    print()


def main():
    """主函数"""
    import argparse
    
    parser = argparse.ArgumentParser(description="EG 打包分析工具")
    parser.add_argument("--generate", action="store_true", help="生成配置建议")
    
    args = parser.parse_args()
    
    if args.generate:
        generate_updated_config()
    else:
        has_issues = analyze_project_structure()
        
        print()
        print("=" * 70)
        if has_issues:
            print("发现潜在问题，请检查上方输出")
            sys.exit(1)
        else:
            print("✓ 分析完成，配置看起来正常")
            sys.exit(0)


if __name__ == "__main__":
    main()
