"""
环境导出工具
自动导出当前Python环境为requirements.txt
"""

import sys
import os
import subprocess
from typing import Tuple, List


def detect_environment() -> dict:
    """检测当前Python环境类型和信息

    Returns:
        dict: 包含环境类型、名称、版本、路径等信息
    """
    env_info = {
        'type': 'system',
        'name': 'system',
        'python_version': f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}",
        'python_path': sys.executable,
        'prefix': sys.prefix
    }

    # 检测 conda 环境
    if os.environ.get('CONDA_DEFAULT_ENV'):
        env_info['type'] = 'conda'
        env_info['name'] = os.environ.get('CONDA_DEFAULT_ENV')
        env_info['prefix'] = os.environ.get('CONDA_PREFIX', sys.prefix)

    # 检测 virtualenv/venv
    elif os.environ.get('VIRTUAL_ENV'):
        env_info['type'] = 'venv'
        env_info['name'] = os.path.basename(os.environ.get('VIRTUAL_ENV', ''))
        env_info['prefix'] = os.environ.get('VIRTUAL_ENV', sys.prefix)

    return env_info


def get_installed_packages() -> str:
    """获取已安装的包列表

    Returns:
        str: pip freeze 的输出
    """
    result = subprocess.run(
        [sys.executable, '-m', 'pip', 'freeze'],
        capture_output=True,
        text=True,
        check=True
    )
    return result.stdout.strip()


def clean_package_line(line: str) -> str:
    """清理包行，处理特殊格式

    处理:
    - package @ file:///path/to/file
    - package @ git+https://...
    - package @ http://...
    - -e git+...#egg=package

    Args:
        line: 原始包行

    Returns:
        str: 清理后的包行，格式为 package==version 或 package
    """
    line = line.strip()

    # 处理 -e git+ 格式（editable install）
    if line.startswith('-e '):
        # -e git+https://github.com/user/repo.git@main#egg=package
        if '#egg=' in line:
            package_name = line.split('#egg=')[1].strip()
            try:
                import importlib.metadata
                version = importlib.metadata.version(package_name)
                return f"{package_name}=={version}"
            except Exception:
                return package_name
        return None  # 跳过无法处理的

    # 处理 @ 格式（file://, git+, http://等）
    if ' @ ' in line:
        package_name = line.split(' @ ')[0].strip()

        # 尝试获取已安装的版本
        try:
            import importlib.metadata
            version = importlib.metadata.version(package_name)
            return f"{package_name}=={version}"
        except Exception:
            # 无法获取版本，只保留包名
            return package_name

    return line


def filter_packages(packages_str: str, no_filter: bool = False) -> Tuple[str, int, int]:
    """智能过滤包列表

    Args:
        packages_str: pip freeze 的原始输出
        no_filter: 是否禁用过滤

    Returns:
        tuple: (过滤后的包列表, 原始包数量, 过滤后包数量)
    """
    lines = packages_str.split('\n')
    original_count = len([l for l in lines if l.strip() and not l.startswith('#')])

    if no_filter:
        # 即使不过滤，也要清理特殊格式
        cleaned_lines = []
        for line in lines:
            line = line.strip()
            if not line or line.startswith('#'):
                cleaned_lines.append(line)
                continue

            cleaned = clean_package_line(line)
            if cleaned:
                cleaned_lines.append(cleaned)

        return '\n'.join(cleaned_lines), original_count, len([l for l in cleaned_lines if l.strip() and not l.startswith('#')])

    # 需要排除的包列表
    EXCLUDE_PACKAGES = [
        # inoyb 本身
        'inoyb',

        # 包管理工具
        'pip',
        'setuptools',
        'wheel',
        'packaging',

        # Jupyter 相关
        'jupyter',
        'jupyter-core',
        'jupyter-client',
        'jupyter-server',
        'jupyterlab',
        'notebook',
        'ipython',
        'ipykernel',
        'ipywidgets',

        # 开发工具
        'pytest',
        'pytest-cov',
        'coverage',
        'black',
        'flake8',
        'pylint',
        'mypy',
        'autopep8',
        'isort',
        'yapf',

        # 文档工具
        'sphinx',
        'sphinx-rtd-theme',

        # IDE 插件
        'jedi',
        'rope',
        'python-language-server',

        # 其他常见开发工具
        'pre-commit',
        'tox',
        'virtualenv',
    ]

    filtered_lines = []

    for line in lines:
        line = line.strip()

        # 跳过空行和注释
        if not line or line.startswith('#'):
            continue

        # 清理特殊格式
        cleaned_line = clean_package_line(line)
        if not cleaned_line:
            continue

        # 提取包名（处理 package==version 格式）
        package_name = cleaned_line.split('==')[0].split('>=')[0].split('<=')[0].split('@')[0].strip()

        # 检查是否应该排除
        if package_name.lower() in [p.lower() for p in EXCLUDE_PACKAGES]:
            continue

        filtered_lines.append(cleaned_line)

    filtered_packages = '\n'.join(filtered_lines)
    filtered_count = len(filtered_lines)

    return filtered_packages, original_count, filtered_count


def generate_requirements(
    output_path: str = 'requirements.txt',
    no_filter: bool = False
) -> None:
    """生成 requirements.txt 文件

    Args:
        output_path: 输出文件路径
        no_filter: 是否禁用智能过滤
    """
    # 1. 检测环境
    env_info = detect_environment()

    print(f"🔍 检测当前环境")
    print(f"   环境类型: {env_info['type']}")
    print(f"   环境名称: {env_info['name']}")
    print(f"   Python版本: {env_info['python_version']}")
    print(f"   环境路径: {env_info['prefix']}")

    # 2. 获取包列表
    print(f"\n📦 正在导出包列表...")
    try:
        all_packages = get_installed_packages()
    except subprocess.CalledProcessError as e:
        print(f"❌ 获取包列表失败: {e}")
        sys.exit(1)

    # 3. 智能过滤
    packages, original_count, filtered_count = filter_packages(all_packages, no_filter)

    print(f"   已安装包数: {original_count}")
    if not no_filter:
        print(f"   过滤后包数: {filtered_count}")
        print(f"   已排除: {original_count - filtered_count} 个包（开发工具、Jupyter等）")

    # 4. 写入文件
    abs_output_path = os.path.abspath(output_path)
    with open(abs_output_path, 'w', encoding='utf-8') as f:
        f.write(packages)
        if packages and not packages.endswith('\n'):
            f.write('\n')

    print(f"\n✅ 已生成 requirements.txt")
    print(f"   文件路径: {abs_output_path}")
    print(f"   包含包数: {filtered_count}")

    print(f"\n💡 下一步:")
    print(f"   1. 检查 requirements.txt 确认依赖正确")
    print(f"   2. 执行 inoyb build 构建镜像")
