import subprocess
import json
from typing import Optional, List
import structlog

logger = structlog.get_logger()


class DockerManager:
    """Docker 容器管理器，用于隔离执行环境"""

    def __init__(self):
        self.logger = structlog.get_logger().bind(component="docker_manager")

    def is_available(self) -> bool:
        try:
            r = subprocess.run(["docker", "info"], capture_output=True, timeout=10)
            return r.returncode == 0
        except (FileNotFoundError, subprocess.TimeoutExpired):
            return False

    def run_container(
        self,
        image: str,
        command: List[str],
        volumes: Optional[dict] = None,
        env: Optional[dict] = None,
        timeout: int = 300,
        remove: bool = True,
    ) -> dict:
        """
        运行 Docker 容器

        Args:
            image: Docker 镜像名
            command: 容器命令
            volumes: {host_path: container_path}
            env: 环境变量
            timeout: 超时秒数
            remove: 结束后是否删除容器

        Returns:
            dict with stdout, stderr, exit_code, success
        """
        cmd = ["docker", "run"]
        if remove:
            cmd.append("--rm")

        if volumes:
            for host, container in volumes.items():
                cmd += ["-v", f"{host}:{container}"]

        if env:
            for k, v in env.items():
                cmd += ["-e", f"{k}={v}"]

        cmd.append(image)
        cmd.extend(command)

        try:
            result = subprocess.run(
                cmd,
                capture_output=True,
                text=True,
                timeout=timeout,
            )
            return {
                "success": result.returncode == 0,
                "stdout": result.stdout,
                "stderr": result.stderr,
                "exit_code": result.returncode,
            }
        except subprocess.TimeoutExpired:
            return {"success": False, "stdout": "", "stderr": f"Timeout ({timeout}s)", "exit_code": -1}
        except Exception as e:
            return {"success": False, "stdout": "", "stderr": str(e), "exit_code": -1}

    def pull_image(self, image: str) -> bool:
        result = subprocess.run(["docker", "pull", image], capture_output=True, text=True, timeout=120)
        return result.returncode == 0

    def image_exists(self, image: str) -> bool:
        result = subprocess.run(
            ["docker", "image", "inspect", image],
            capture_output=True,
            timeout=10,
        )
        return result.returncode == 0

    def list_containers(self) -> list:
        result = subprocess.run(
            ["docker", "ps", "--format", "json"],
            capture_output=True,
            text=True,
        )
        containers = []
        for line in result.stdout.strip().splitlines():
            try:
                containers.append(json.loads(line))
            except json.JSONDecodeError:
                pass
        return containers
