"""Data models for sandbox security policies and container configuration."""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any


@dataclass
class NetworkPolicy:
    """Network access policy for a sandboxed container.

    When ``enabled`` is False, the container has no network access at all
    (equivalent to Docker's ``network_mode="none"``).  When True, only the
    domains listed in ``allowed_domains`` may be contacted.  An empty
    ``allowed_domains`` list with ``enabled=True`` means *all* domains are
    permitted (used by the ``permissive`` preset).
    """

    enabled: bool = False
    allowed_domains: list[str] = field(default_factory=list)


@dataclass
class FilesystemPolicy:
    """Filesystem access policy for a sandboxed container.

    ``read_only_mounts`` are bind-mounted into the container as read-only.
    ``writable_dirs`` are mounted as tmpfs volumes so the tool can write
    temporary data without persisting anything to the host.
    """

    read_only_mounts: list[str] = field(default_factory=list)
    writable_dirs: list[str] = field(default_factory=list)


@dataclass
class ResourceLimits:
    """CPU, memory, and timeout constraints for a sandboxed container.

    ``cpu_limit`` is a fractional CPU string (e.g. ``"0.5"`` for half a core).
    ``memory_limit`` uses Docker's notation (e.g. ``"256m"``, ``"1g"``).
    ``timeout_seconds`` is a hard deadline — the container is killed if
    execution exceeds this.
    """

    cpu_limit: str = "1.0"
    memory_limit: str = "512m"
    timeout_seconds: int = 30


@dataclass
class SandboxPolicy:
    """Complete security policy governing sandbox behaviour.

    ``name`` is one of the built-in presets (``"strict"``, ``"standard"``,
    ``"permissive"``) or ``"custom"`` when the user supplies their own
    overrides.
    """

    name: str
    network: NetworkPolicy
    filesystem: FilesystemPolicy
    resources: ResourceLimits


@dataclass
class ContainerConfig:
    """Docker/OCI container configuration derived from a ``SandboxPolicy``.

    This is the intermediate representation between a high-level
    ``SandboxPolicy`` and the low-level Docker SDK calls.
    """

    image: str = ""
    network_mode: str = "none"
    dns_servers: list[str] = field(default_factory=list)
    allowed_domains: list[str] = field(default_factory=list)
    volumes: dict[str, dict[str, str]] = field(default_factory=dict)
    tmpfs: dict[str, str] = field(default_factory=dict)
    mem_limit: str = "512m"
    cpu_period: int = 100_000
    cpu_quota: int = 100_000
    timeout_seconds: int = 30
    labels: dict[str, str] = field(default_factory=dict)
    environment: dict[str, str] = field(default_factory=dict)
    entrypoint: list[str] | None = None
    command: list[str] | None = None
    ports: dict[str, int] = field(default_factory=dict)
    extra_hosts: list[str] = field(default_factory=list)
    cap_add: list[str] = field(default_factory=list)


@dataclass
class ContainerStats:
    """Resource usage snapshot from a running container."""

    container_id: str
    memory_usage_bytes: int = 0
    memory_limit_bytes: int = 0
    cpu_percent: float = 0.0

    @property
    def memory_usage_mb(self) -> float:
        """Memory usage in megabytes."""
        return self.memory_usage_bytes / (1024 * 1024)

    @property
    def memory_percent(self) -> float:
        """Memory usage as a percentage of the limit."""
        if self.memory_limit_bytes == 0:
            return 0.0
        return (self.memory_usage_bytes / self.memory_limit_bytes) * 100


@dataclass
class SandboxResult:
    """The outcome of executing a tool call inside the sandbox."""

    tool_name: str
    arguments: dict[str, Any]
    content: list[dict[str, Any]] = field(default_factory=list)
    is_error: bool = False
    latency_ms: float = 0.0
    container_id: str = ""
    stats: ContainerStats | None = None
