"""Docker sandbox utilities for agent execution."""

from __future__ import annotations

import subprocess
import sys
from dataclasses import dataclass
from enum import StrEnum
from pathlib import Path

from ievo.core.agent import AgentPackage


class DockerStatus(StrEnum):
    """Docker availability status."""

    READY = "ready"
    NOT_INSTALLED = "not_installed"
    NOT_RUNNING = "not_running"


SANDBOX_IMAGE = "ievoai/sandbox:latest"


@dataclass
class DockerCheckResult:
    """Result of checking Docker availability."""

    status: DockerStatus
    message: str


def check_docker() -> DockerCheckResult:
    """Check if Docker is installed and daemon is running."""
    try:
        result = subprocess.run(
            ["docker", "version", "--format", "{{.Server.Version}}"],
            capture_output=True,
            text=True,
            timeout=10,
        )
        if result.returncode != 0:
            return DockerCheckResult(
                status=DockerStatus.NOT_RUNNING,
                message="Docker daemon is not running. Start Docker Desktop or dockerd.",
            )
        return DockerCheckResult(
            status=DockerStatus.READY,
            message=f"Docker {result.stdout.strip()}",
        )
    except FileNotFoundError:
        return DockerCheckResult(
            status=DockerStatus.NOT_INSTALLED,
            message="Docker not found. Install: https://docs.docker.com/get-docker/",
        )
    except subprocess.TimeoutExpired:
        return DockerCheckResult(
            status=DockerStatus.NOT_RUNNING,
            message="Docker command timed out. Is the daemon running?",
        )


def image_exists(image: str = SANDBOX_IMAGE) -> bool:
    """Check if a Docker image exists locally."""
    result = subprocess.run(
        ["docker", "image", "inspect", image],
        capture_output=True,
        timeout=10,
    )
    return result.returncode == 0


def build_sandbox_image(dockerfile_dir: Path, image: str = SANDBOX_IMAGE) -> bool:
    """Build the sandbox Docker image from a Dockerfile directory.

    Returns True if build succeeded.
    """
    result = subprocess.run(
        ["docker", "build", "-t", image, str(dockerfile_dir)],
        timeout=600,
    )
    return result.returncode == 0


def build_docker_command(
    root: Path,
    agent_dir: Path,
    pkg: AgentPackage,
    model: str,
    message: str | None,
    prompt_file: Path | None,
    image: str = SANDBOX_IMAGE,
) -> list[str]:
    """Build a docker run command for agent execution."""
    # Resolve allowed tools — add WebFetch/WebSearch if network enabled
    tools = list(pkg.sandbox.allowed_tools)
    if pkg.sandbox.network:
        for tool in ["WebFetch", "WebSearch"]:
            if tool not in tools:
                tools.append(tool)

    # Docker run command
    cmd = ["docker", "run", "--rm"]

    # TTY handling
    if sys.stdout.isatty():
        cmd.append("-it")
    else:
        cmd.append("-i")

    # Volume mount — project root into /workspace
    cmd.extend(["-v", f"{root}:/workspace", "-w", "/workspace"])

    # Pass OAuth token for Claude CLI auth
    cmd.extend(["-e", "CLAUDE_CODE_OAUTH_TOKEN"])

    # Resource limits
    cmd.extend(["--memory", f"{pkg.sandbox.memory_mb}m"])
    cmd.extend(["--cpus", str(pkg.sandbox.cpu_limit)])

    # Image
    cmd.append(image)

    # Claude CLI arguments inside container
    model_map = {"opus": "opus", "sonnet": "sonnet", "haiku": "haiku"}
    if model in model_map:
        cmd.extend(["--model", model_map[model]])

    # System prompt from ROLE.md
    role_md = agent_dir / "ROLE.md"
    if role_md.exists():
        cmd.extend(["--system-prompt", role_md.read_text()])

    # Append memory context
    memory_dir = agent_dir / "memory"
    if memory_dir.exists():
        memory_context = []
        for mf in sorted(memory_dir.glob("*.md")):
            content = mf.read_text().strip()
            if content and content != f"# {mf.stem}":
                memory_context.append(f"## {mf.stem}\n\n{content}")
        if memory_context:
            cmd.extend(["--append-system-prompt", "\n\n---\n\n".join(memory_context)])

    # Tool restrictions
    cmd.extend(["--allowedTools", ",".join(tools)])

    # Initial message
    if prompt_file:
        cmd.extend(["-p", prompt_file.read_text()])
    elif message:
        cmd.extend(["-p", message])

    return cmd
