"""Container configuration and state models."""

from __future__ import annotations

from datetime import datetime
from enum import Enum
from typing import Annotated

from pydantic import BaseModel, Field

from gaol.gpu.models import DeviceMapping, GPUConfig


class NetworkMode(str, Enum):
    """Network mode for containers."""

    SHARED = "shared"  # NAT/shared networking (default)
    BRIDGED = "bridged"  # Direct network access with own IP
    HOST = "host"  # Share host network namespace
    NONE = "none"  # No networking


class ContainerStatus(str, Enum):
    """Container runtime status."""

    CREATED = "created"
    RUNNING = "running"
    PAUSED = "paused"
    STOPPED = "stopped"
    EXITED = "exited"
    DEAD = "dead"
    UNKNOWN = "unknown"


class NetworkConfig(BaseModel):
    """Network configuration for a container."""

    mode: NetworkMode = NetworkMode.SHARED
    ports: Annotated[
        dict[int, int],
        Field(default_factory=dict, description="Host port -> container port mapping"),
    ]
    dns: Annotated[list[str], Field(default_factory=list, description="Custom DNS servers")]
    hostname: str | None = None


class ResourceLimits(BaseModel):
    """Resource limits for a container."""

    memory_mb: Annotated[int | None, Field(None, ge=0, description="Memory limit in MB")]
    cpu_shares: Annotated[int | None, Field(None, ge=0, description="CPU shares (relative weight)")]
    cpu_count: Annotated[float | None, Field(None, ge=0, description="Number of CPUs")]
    disk_mb: Annotated[int | None, Field(None, ge=0, description="Disk space limit in MB")]


class UserConfig(BaseModel):
    """User configuration for a container."""

    name: Annotated[str, Field(min_length=1, max_length=32, description="Username")]
    uid: Annotated[int | None, Field(None, ge=0, le=65534, description="User ID")]
    gid: Annotated[int | None, Field(None, ge=0, le=65534, description="Primary group ID")]
    groups: Annotated[list[str], Field(default_factory=list, description="Additional groups")]
    home: Annotated[str | None, Field(None, description="Home directory path")]
    shell: Annotated[str, Field(default="/bin/bash", description="Login shell")]
    create_home: Annotated[bool, Field(default=True, description="Create home directory")]


class ServiceConfig(BaseModel):
    """Systemd service configuration for a container."""

    name: Annotated[str, Field(min_length=1, max_length=64, description="Service name")]
    command: Annotated[str, Field(min_length=1, description="Command to run")]
    user: Annotated[str, Field(default="root", description="User to run the service as")]
    workdir: Annotated[str | None, Field(None, description="Working directory")]
    description: Annotated[str | None, Field(None, description="Service description")]
    restart: Annotated[str, Field(default="on-failure", description="Restart policy")]
    environment: Annotated[
        dict[str, str], Field(default_factory=dict, description="Environment variables")
    ]
    enabled: Annotated[bool, Field(default=True, description="Enable service on boot")]


class ContainerConfig(BaseModel):
    """Configuration for creating a container."""

    name: Annotated[
        str, Field(min_length=1, max_length=64, pattern=r"^[a-zA-Z0-9][a-zA-Z0-9_.-]*$")
    ]
    runtime: Annotated[str, Field(default="docker", description="Container runtime to use")]
    distro: Annotated[str, Field(default="trixie", description="Base distribution")]
    image: str | None = None  # Custom image override
    profiles: Annotated[
        list[str], Field(default_factory=list, description="Profile names to apply")
    ]
    network: NetworkConfig = Field(default_factory=NetworkConfig)
    resources: ResourceLimits = Field(default_factory=ResourceLimits)
    volumes: Annotated[
        dict[str, str],
        Field(default_factory=dict, description="Host path -> container path volume mounts"),
    ]
    environment: Annotated[
        dict[str, str], Field(default_factory=dict, description="Environment variables")
    ]
    working_dir: str | None = None
    command: list[str] | None = None
    privileged: bool = False
    read_only: bool = False
    private_users: Annotated[
        bool, Field(default=True, description="Use user namespace (nspawn). Set False for GUI containers.")
    ]
    # GPU and device passthrough
    gpu: Annotated[GPUConfig | None, Field(default=None, description="GPU configuration")]
    devices: Annotated[
        list[DeviceMapping],
        Field(default_factory=list, description="Device passthrough mappings"),
    ]
    # Users and services
    users: Annotated[
        list[UserConfig],
        Field(default_factory=list, description="Users to create in the container"),
    ]
    services: Annotated[
        list[ServiceConfig],
        Field(default_factory=list, description="Systemd services to create"),
    ]
    packages: Annotated[
        list[str],
        Field(default_factory=list, description="Packages to install in the container"),
    ]
    setup_commands: Annotated[
        list[str],
        Field(default_factory=list, description="Commands to run before package installation"),
    ]


class ContainerState(BaseModel):
    """Current state of a container."""

    id: str
    name: str
    runtime: str
    status: ContainerStatus
    image: str
    created_at: datetime | None = None
    started_at: datetime | None = None
    finished_at: datetime | None = None
    exit_code: int | None = None
    error: str | None = None
    ip_address: str | None = None
    ports: dict[int, int] = Field(default_factory=dict)
    profiles: list[str] = Field(default_factory=list)


class Snapshot(BaseModel):
    """Container snapshot information."""

    id: str
    name: str
    container_id: str
    container_name: str
    created_at: datetime
    size_bytes: int | None = None
    description: str | None = None


class ContainerStats(BaseModel):
    """Container resource usage statistics."""

    container_id: str
    container_name: str
    timestamp: datetime = Field(default_factory=datetime.now)

    # CPU
    cpu_percent: float = 0.0  # CPU usage percentage (0-100 per core)
    cpu_count: int | None = None  # Number of CPUs available

    # Memory
    memory_used_bytes: int = 0
    memory_limit_bytes: int | None = None
    memory_percent: float = 0.0  # Memory usage percentage

    # Network I/O
    network_rx_bytes: int = 0  # Bytes received
    network_tx_bytes: int = 0  # Bytes transmitted

    # Block I/O
    block_read_bytes: int = 0  # Bytes read from disk
    block_write_bytes: int = 0  # Bytes written to disk

    # Process count
    pids: int = 0  # Number of processes/threads

    @property
    def memory_used_mb(self) -> float:
        """Memory used in MB."""
        return self.memory_used_bytes / (1024 * 1024)

    @property
    def memory_limit_mb(self) -> float | None:
        """Memory limit in MB."""
        if self.memory_limit_bytes is None:
            return None
        return self.memory_limit_bytes / (1024 * 1024)


class HealthStatus(str, Enum):
    """Container health check status."""

    HEALTHY = "healthy"
    UNHEALTHY = "unhealthy"
    STARTING = "starting"
    UNKNOWN = "unknown"


class HealthCheck(BaseModel):
    """Health check configuration."""

    command: list[str]  # Command to run for health check
    interval_seconds: int = 30  # Time between checks
    timeout_seconds: int = 10  # Timeout for each check
    retries: int = 3  # Failures before unhealthy
    start_period_seconds: int = 0  # Grace period after start


class HealthCheckResult(BaseModel):
    """Result of a health check."""

    status: HealthStatus
    check_time: datetime = Field(default_factory=datetime.now)
    exit_code: int | None = None
    output: str | None = None
    consecutive_failures: int = 0
