import asyncio
from pathlib import Path
import subprocess
from subprocess import CalledProcessError
from typing import ClassVar

from zhenxun.configs.config import Config
from zhenxun.services.log import logger

BAT_FILE = Path() / "win启动.bat"

LOG_COMMAND = "VirtualEnvPackageManager"

Config.add_plugin_config(
    "virtualenv",
    "python_path",
    None,
    help="虚拟环境python路径，为空时使用系统环境的poetry",
)


class VirtualEnvPackageManager:
    WIN_COMMAND: ClassVar[list[str]] = [
        "./Python310/python.exe",
        "-m",
        "pip",
    ]

    DEFAULT_COMMAND: ClassVar[list[str]] = ["poetry", "run", "pip"]

    @classmethod
    def __get_command(cls) -> list[str]:
        if path := Config.get_config("virtualenv", "python_path"):
            return [path, "-m", "pip"]
        return (
            cls.WIN_COMMAND.copy() if BAT_FILE.exists() else cls.DEFAULT_COMMAND.copy()
        )

    @classmethod
    async def install(cls, package: list[str] | str):
        """安装依赖包

        参数:
            package: 安装依赖包名称或列表
        """
        if isinstance(package, str):
            package = [package]
        try:
            command = cls.__get_command()
            command.append("install")
            command.append(" ".join(package))
            logger.info(f"执行虚拟环境安装包指令: {command}", LOG_COMMAND)
            result = await asyncio.to_thread(
                subprocess.run,
                command,
                check=True,
                capture_output=True,
                text=True,
            )
            logger.debug(
                f"安装虚拟环境包指令执行完成: {result.stdout}",
                LOG_COMMAND,
            )
            return result.stdout
        except CalledProcessError as e:
            logger.error(f"安装虚拟环境包指令执行失败: {e.stderr}.", LOG_COMMAND)
            return e.stderr

    @classmethod
    async def uninstall(cls, package: list[str] | str):
        """卸载依赖包

        参数:
            package: 卸载依赖包名称或列表
        """
        if isinstance(package, str):
            package = [package]
        try:
            command = cls.__get_command()
            command.append("uninstall")
            command.append("-y")
            command.append(" ".join(package))
            logger.info(f"执行虚拟环境卸载包指令: {command}", LOG_COMMAND)
            result = await asyncio.to_thread(
                subprocess.run,
                command,
                check=True,
                capture_output=True,
                text=True,
            )
            logger.debug(
                f"卸载虚拟环境包指令执行完成: {result.stdout}",
                LOG_COMMAND,
            )
            return result.stdout
        except CalledProcessError as e:
            logger.error(f"卸载虚拟环境包指令执行失败: {e.stderr}.", LOG_COMMAND)
            return e.stderr

    @classmethod
    async def update(cls, package: list[str] | str):
        """更新依赖包

        参数:
            package: 更新依赖包名称或列表
        """
        if isinstance(package, str):
            package = [package]
        try:
            command = cls.__get_command()
            command.append("install")
            command.append("--upgrade")
            command.append(" ".join(package))
            logger.info(f"执行虚拟环境更新包指令: {command}", LOG_COMMAND)
            result = await asyncio.to_thread(
                subprocess.run,
                command,
                check=True,
                capture_output=True,
                text=True,
            )
            logger.debug(f"更新虚拟环境包指令执行完成: {result.stdout}", LOG_COMMAND)
            return result.stdout
        except CalledProcessError as e:
            logger.error(f"更新虚拟环境包指令执行失败: {e.stderr}.", LOG_COMMAND)
            return e.stderr

    @classmethod
    async def install_requirement(cls, requirement_file: Path):
        """安装依赖文件

        参数:
            requirement_file: requirement文件路径

        异常:
            FileNotFoundError: 文件不存在
        """
        if not requirement_file.exists():
            raise FileNotFoundError(f"依赖文件 {requirement_file} 不存在", LOG_COMMAND)
        try:
            command = cls.__get_command()
            command.append("install")
            command.append("-r")
            command.append(str(requirement_file.absolute()))
            logger.info(f"执行虚拟环境安装依赖文件指令: {command}", LOG_COMMAND)
            result = await asyncio.to_thread(
                subprocess.run,
                command,
                check=True,
                capture_output=True,
                text=True,
            )
            logger.debug(
                f"安装虚拟环境依赖文件指令执行完成: {result.stdout}",
                LOG_COMMAND,
            )
            return result.stdout
        except CalledProcessError as e:
            logger.error(
                f"安装虚拟环境依赖文件指令执行失败: {e.stderr}.",
                LOG_COMMAND,
            )
            return e.stderr

    @classmethod
    async def list(cls) -> str:
        """列出已安装的依赖包"""
        try:
            command = cls.__get_command()
            command.append("list")
            logger.info(f"执行虚拟环境列出包指令: {command}", LOG_COMMAND)
            result = await asyncio.to_thread(
                subprocess.run,
                command,
                check=True,
                capture_output=True,
                text=True,
            )
            logger.debug(
                f"列出虚拟环境包指令执行完成: {result.stdout}",
                LOG_COMMAND,
            )
            return result.stdout
        except CalledProcessError as e:
            logger.error(f"列出虚拟环境包指令执行失败: {e.stderr}.", LOG_COMMAND)
        return ""
