"""
Container Runtime — Docker container lifecycle management for ABI.

Abstracts container creation, health checking, and destruction.
Used by the builder (create ephemeral agents) and orchestrator (cleanup).

Usage:
    from abi_core.common.container_runtime import run_container, destroy_container

    result = await run_container(
        name="ephemeral_task_1",
        image="smarbuy/abi-image:latest",
        env_vars={"ZOMBIE_MODE": "active", "AGENT_NAME": "task_1"},
        network="abi_network",
        port=11440,
        entrypoint="python3",
        command=["/opt/abi/zombie/main.py"],
        health_check_url="http://localhost:11440/health",
    )

    await destroy_container("ephemeral_task_1")
"""

import asyncio
from typing import Any, Dict, List, Optional

from abi_core.common.utils import abi_logging


async def check_container_health(
    url: str, timeout: int = 30, interval: float = 1.0
) -> bool:
    """Poll a health endpoint until ready or timeout."""
    import urllib.request

    for attempt in range(int(timeout / interval)):
        try:
            req = urllib.request.Request(url, method="GET")
            urllib.request.urlopen(req, timeout=2)
            abi_logging(f"[✅] Health check passed: {url}")
            return True
        except Exception:
            await asyncio.sleep(interval)
    abi_logging(f"[⚠️] Health check timeout after {timeout}s: {url}")
    return False


async def run_container(
    name: str,
    image: str,
    env_vars: Optional[Dict[str, str]] = None,
    network: Optional[str] = None,
    port: Optional[int] = None,
    entrypoint: Optional[str] = None,
    command: Optional[List[str]] = None,
    health_check_url: Optional[str] = None,
    health_timeout: int = 30,
) -> Dict[str, Any]:
    """Run a Docker container and optionally wait for health.

    Returns dict with status, container_id, name, url, port.
    """
    docker_cmd = ["docker", "run", "-d", "--name", name]

    if network:
        docker_cmd.extend(["--network", network])

    if port:
        docker_cmd.extend(["-p", f"{port}:{port}"])

    for key, val in (env_vars or {}).items():
        docker_cmd.extend(["-e", f"{key}={val}"])

    if entrypoint:
        docker_cmd.extend(["--entrypoint", entrypoint])

    docker_cmd.append(image)

    if command:
        docker_cmd.extend(command)

    abi_logging(f"[🐳] Running container '{name}' from {image}")

    proc = await asyncio.create_subprocess_exec(
        *docker_cmd,
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE,
    )
    stdout, stderr = await proc.communicate()

    if proc.returncode != 0:
        error_msg = stderr.decode().strip()
        abi_logging(f"[❌] Container '{name}' failed to start: {error_msg}")
        return {
            "status": "error",
            "name": name,
            "error": error_msg,
        }

    container_id = stdout.decode().strip()[:12]
    abi_logging(f"[✅] Container '{name}' started (id: {container_id})")

    healthy = True
    if health_check_url:
        healthy = await check_container_health(
            health_check_url, timeout=health_timeout
        )

    url = f"http://{name}:{port}" if port else None

    return {
        "status": "running" if healthy else "unhealthy",
        "container_id": container_id,
        "name": name,
        "url": url,
        "port": port,
        "healthy": healthy,
    }


async def destroy_container(name: str) -> bool:
    """Stop and remove a container by name."""
    abi_logging(f"[🗑️] Destroying container '{name}'")

    proc = await asyncio.create_subprocess_exec(
        "docker", "rm", "-f", name,
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE,
    )
    await proc.communicate()

    if proc.returncode == 0:
        abi_logging(f"[✅] Container '{name}' destroyed")
        return True

    abi_logging(f"[⚠️] Could not destroy '{name}' (may already be gone)")
    return False
