#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Portal 环境构建脚本（全平台兼容：Windows/Linux）
特性：
1. 自动识别系统类型，适配 Conda 执行逻辑
2. 智能跳过已完成步骤（环境/uv/依赖）
3. 自动处理 uv.lock 锁文件（首次不加 --frozen）
4. 兼容 Conda 初始化、路径分隔符、权限等问题
"""

import subprocess
import sys
import argparse
import os
import re
import platform

# 跨平台彩色输出兼容
try:
    from colorama import init, Fore, Style

    # Windows 初始化 colorama，Linux 无需
    if platform.system() == "Windows":
        init(autoreset=True)
except ImportError:
    # 无 colorama 时降级为无颜色输出
    class FakeColor:
        def __getattr__(self, name):
            return ""


    Fore = FakeColor()
    Style = FakeColor()


class EnvBuilderError(Exception):
    """自定义异常类"""
    pass


def get_conda_init_cmd():
    """获取对应系统的 Conda 初始化命令"""
    system = platform.system()
    if system == "Linux":
        # Linux 下 Conda 初始化路径（兼容 Miniconda/Anaconda）
        conda_paths = [
            "~/miniconda3/etc/profile.d/conda.sh",
            "~/anaconda3/etc/profile.d/conda.sh",
            "/opt/conda/etc/profile.d/conda.sh"
        ]
        for path in conda_paths:
            abs_path = os.path.expanduser(path)
            if os.path.exists(abs_path):
                return f"source {abs_path} && "
        return "source ~/miniconda3/etc/profile.d/conda.sh && "  # 默认路径
    return ""  # Windows 无需初始化


def run_command(cmd, description, check_only=False):
    """
    执行系统命令（全平台兼容）
    check_only=True: 仅检查结果，不抛出异常、不打印冗余输出
    """
    if not check_only:
        print(f"{Fore.BLUE}[*] {description}...{Style.RESET_ALL}")

    system = platform.system()
    try:
        # 构建最终执行的命令
        final_cmd = cmd
        if system == "Linux" and cmd[0] == "conda":
            # Linux 下：封装 Conda 命令，确保初始化 + bash 执行
            conda_init = get_conda_init_cmd()
            cmd_str = conda_init + " ".join(cmd)
            final_cmd = ["bash", "-c", cmd_str]
            shell = False
        else:
            # Windows 下：启用 shell 以支持 conda 命令
            shell = system == "Windows"

        # 执行命令
        result = subprocess.run(
            final_cmd,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            text=True,
            encoding="utf-8",
            errors="ignore",
            shell=shell
        )

        # 打印输出（非检查模式）
        if not check_only and result.stdout:
            print(f"{Fore.GREEN}[+] 输出: {result.stdout}{Style.RESET_ALL}")

        # 返回执行结果
        return result.returncode == 0, result.stdout

    except Exception as e:
        if check_only:
            return False, str(e)
        raise EnvBuilderError(f"{Fore.RED}[-] 执行{description}出错: {str(e)}{Style.RESET_ALL}")


def check_conda_env_exists(env_name):
    """检查 Conda 环境是否存在（跨平台）"""
    print(f"{Fore.BLUE}[*] 检查虚拟环境 {env_name} 是否存在...{Style.RESET_ALL}")
    success, output = run_command(
        ["conda", "info", "--envs"],
        f"检查 Conda 环境 {env_name}",
        check_only=True
    )
    if success:
        env_pattern = re.compile(rf"{env_name}\s+")
        if env_pattern.search(output):
            print(f"{Fore.GREEN}[+] 虚拟环境 {env_name} 已存在，跳过创建步骤{Style.RESET_ALL}")
            return True
    print(f"{Fore.YELLOW}[!] 虚拟环境 {env_name} 不存在，需要创建{Style.RESET_ALL}")
    return False


def check_uv_installed(env_name):
    """检查指定 Conda 环境中是否安装 uv（跨平台）"""
    print(f"{Fore.BLUE}[*] 检查环境 {env_name} 中是否安装 uv...{Style.RESET_ALL}")
    cmd = ["conda", "run", "-n", env_name, "uv", "--version"]
    success, output = run_command(cmd, "检查 uv 安装状态", check_only=True)
    if success and "uv " in output:  # 确保输出包含 uv 版本信息（避免误判）
        print(f"{Fore.GREEN}[+] uv 已安装，跳过安装步骤{Style.RESET_ALL}")
        return True
    print(f"{Fore.YELLOW}[!] uv 未安装，需要安装{Style.RESET_ALL}")
    return False


def check_deps_synced(env_name):
    """检查依赖是否已还原（跨平台）"""
    print(f"{Fore.BLUE}[*] 检查依赖是否已还原...{Style.RESET_ALL}")
    # 检查 uv.lock 是否存在 + 依赖是否安装
    if os.path.exists("uv.lock"):
        success, _ = run_command(
            ["conda", "run", "-n", env_name, "uv", "list"],
            "检查依赖列表",
            check_only=True
        )
        if success:
            print(f"{Fore.GREEN}[+] 依赖已还原，跳过 uv sync 步骤{Style.RESET_ALL}")
            return True
    print(f"{Fore.YELLOW}[!] 依赖未还原，需要执行 uv sync{Style.RESET_ALL}")
    return False


def create_portal_env(env_name="portal_test", python_version="3.10.19"):
    """核心功能：智能创建并配置测试环境（全平台）"""
    try:
        # 1. 检查 Conda 是否可用
        conda_ok, conda_output = run_command(["conda", "--version"], "检查 Conda 安装状态", check_only=True)
        if not conda_ok:
            hint = ""
            if platform.system() == "Linux":
                hint = "\n    请先安装 Conda，或执行: source ~/miniconda3/etc/profile.d/conda.sh"
            elif platform.system() == "Windows":
                hint = "\n    请确保 Conda 已添加到系统 PATH 中"
            raise EnvBuilderError(f"{Fore.RED}未检测到 Conda！{hint}{Style.RESET_ALL}")

        # 2. 检查并创建虚拟环境
        env_exists = check_conda_env_exists(env_name)
        if not env_exists:
            run_command(
                ["conda", "create", "-n", env_name, f"python={python_version}", "-y"],
                f"创建虚拟环境 {env_name} (Python {python_version})"
            )

        # 3. 检查并安装 uv（Linux 加 --user 避免权限问题）
        uv_installed = check_uv_installed(env_name)
        if not uv_installed:
            install_cmd = ["conda", "run", "-n", env_name, "pip", "install", "uv"]
            if platform.system() == "Linux":
                install_cmd.append("--user")
            run_command(install_cmd, "安装 uv 包管理器")

        # 4. 检查 pyproject.toml 是否存在
        if not os.path.exists("pyproject.toml"):
            raise EnvBuilderError(f"{Fore.RED}当前目录未找到 pyproject.toml 文件！{Style.RESET_ALL}")

        # 5. 检查并执行 uv sync（跨平台适配）
        deps_synced = check_deps_synced(env_name)
        if not deps_synced:
            uv_sync_cmd = ["conda", "run", "-n", env_name, "uv", "sync"]
            # Linux 下强制指定 Python 解释器路径（动态拼接）
            if platform.system() == "Linux":
                # 自动获取 conda 环境路径
                conda_env_path = os.path.expanduser(f"~/miniconda3/envs/{env_name}/bin/python")
                uv_sync_cmd.extend(["--python", conda_env_path])
            run_command(uv_sync_cmd, "还原线上环境依赖")

        # 执行完成提示（区分系统）
        print(f"\n{Fore.GREEN}[✓] 环境检查/构建完成！{Style.RESET_ALL}")
        activate_hint = ""
        if platform.system() == "Linux":
            activate_hint = f"source activate {env_name}"
        elif platform.system() == "Windows":
            activate_hint = f"conda activate {env_name}"
        print(f"{Fore.YELLOW}[提示] 手动激活环境：{activate_hint}{Style.RESET_ALL}")

    except EnvBuilderError as e:
        print(f"\n{Fore.RED}[✗] 环境构建失败：{str(e)}{Style.RESET_ALL}")
        sys.exit(1)
    except KeyboardInterrupt:
        print(f"\n{Fore.YELLOW}[!] 用户中断操作{Style.RESET_ALL}")
        sys.exit(0)


def main():
    """命令行参数解析和入口（全平台）"""
    parser = argparse.ArgumentParser(
        description="Portal 测试环境一键构建工具（Windows/Linux 通用）",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="示例:\n  python env_builder.py\n  python env_builder.py --env-name my_env --python 3.10.20"
    )
    parser.add_argument(
        "--env-name",
        default="portal_test",
        help="虚拟环境名称（默认：portal_test）"
    )
    parser.add_argument(
        "--python",
        default="3.10.19",
        help="Python 版本（默认：3.10.19）"
    )

    args = parser.parse_args()

    # 检查 Python 版本
    if sys.version_info < (3, 10):
        print(f"{Fore.RED}[-] 该脚本需要 Python 3.10 及以上版本！{Style.RESET_ALL}")
        sys.exit(1)

    create_portal_env(env_name=args.env_name, python_version=args.python)


if __name__ == "__main__":
    main()