"""Container group models for pod-like orchestration."""

from __future__ import annotations

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

from pydantic import BaseModel, Field, model_validator

from gaol.models.container import ContainerStatus


class HealthCheckType(str, Enum):
    """Type of health check."""

    HTTP = "http"
    TCP = "tcp"
    COMMAND = "command"


class HealthCheckConfig(BaseModel):
    """Health check configuration for a container in a group."""

    type: HealthCheckType = HealthCheckType.TCP
    # For HTTP checks
    path: str | None = None
    port: int | None = None
    # For command checks
    command: list[str] | None = None
    # Timing
    interval: int = 10  # Seconds between checks
    timeout: int = 5  # Seconds to wait for response
    retries: int = 3  # Failures before unhealthy
    start_period: int = 0  # Grace period after start

    @model_validator(mode="after")
    def validate_check_type(self) -> HealthCheckConfig:
        """Validate that required fields are set for each check type."""
        if self.type == HealthCheckType.HTTP:
            if self.port is None:
                raise ValueError("HTTP health check requires 'port'")
            if self.path is None:
                self.path = "/"
        elif self.type == HealthCheckType.TCP:
            if self.port is None:
                raise ValueError("TCP health check requires 'port'")
        elif self.type == HealthCheckType.COMMAND:
            if not self.command:
                raise ValueError("Command health check requires 'command'")
        return self


class ContainerRef(BaseModel):
    """Reference to a container within a group.

    This defines a container's configuration within a group spec,
    similar to a service in docker-compose.
    """

    # Basic settings
    image: str
    runtime: str = "docker"

    # Profiles to apply
    profiles: list[str] = Field(default_factory=list)

    # Environment variables
    environment: dict[str, str] = Field(default_factory=dict)

    # Port mappings (host:container format strings)
    ports: list[str] = Field(default_factory=list)

    # Volume mounts (host:container format strings)
    volumes: list[str] = Field(default_factory=list)

    # Dependencies (other container names in the group)
    depends_on: list[str] = Field(default_factory=list)

    # Health check for startup ordering
    healthcheck: HealthCheckConfig | None = None

    # Command override
    command: list[str] | str | None = None

    # Working directory
    working_dir: str | None = None

    # Resource limits
    memory: str | None = None  # e.g., "512M", "2G"
    cpus: float | None = None


class GroupState(str, Enum):
    """State of a container group."""

    CREATED = "created"  # Group saved but not started
    STARTING = "starting"  # Containers being started
    RUNNING = "running"  # All containers running
    PARTIALLY_RUNNING = "partially_running"  # Some containers running
    STOPPING = "stopping"  # Containers being stopped
    STOPPED = "stopped"  # All containers stopped
    ERROR = "error"  # Error state


class MemberStatus(BaseModel):
    """Status of a container within a group."""

    name: str  # Container name within the group
    full_name: str  # Full container name (group-name)
    state: ContainerStatus
    runtime: str
    container_id: str | None = None
    health: str | None = None  # healthy, unhealthy, starting, none
    ip_address: str | None = None
    ports: dict[int, int] = Field(default_factory=dict)


class GroupStatus(BaseModel):
    """Current status of a container group."""

    name: str
    state: GroupState
    containers: list[MemberStatus] = Field(default_factory=list)
    network_name: str | None = None
    created_at: datetime | None = None
    started_at: datetime | None = None

    @property
    def running_count(self) -> int:
        """Number of running containers."""
        return sum(1 for c in self.containers if c.state == ContainerStatus.RUNNING)

    @property
    def total_count(self) -> int:
        """Total number of containers."""
        return len(self.containers)


class GroupSpec(BaseModel):
    """Declarative specification for a container group.

    This is the main model for group YAML files, similar to
    docker-compose.yaml but runtime-agnostic.
    """

    name: Annotated[
        str,
        Field(min_length=1, max_length=64, pattern=r"^[a-zA-Z0-9][a-zA-Z0-9_.-]*$"),
    ]

    # Container definitions (name -> config)
    containers: dict[str, ContainerRef]

    # Networking options
    shared_network: bool = True  # Create a shared bridge network
    dns_enabled: bool = True  # Enable DNS-based service discovery

    # Default runtime for all containers (can be overridden per container)
    default_runtime: str = "docker"

    @model_validator(mode="after")
    def validate_dependencies(self) -> GroupSpec:
        """Validate that all depends_on references exist."""
        container_names = set(self.containers.keys())
        for name, container in self.containers.items():
            for dep in container.depends_on:
                if dep not in container_names:
                    raise ValueError(
                        f"Container '{name}' depends on '{dep}' which does not exist in the group"
                    )
                if dep == name:
                    raise ValueError(f"Container '{name}' cannot depend on itself")
        return self

    def get_container_full_name(self, container_name: str) -> str:
        """Get the full container name (group-container)."""
        return f"{self.name}-{container_name}"
