"""Tests for gaol models."""

import pytest
from pydantic import ValidationError

from gaol.models.container import (
    ContainerConfig,
    ContainerState,
    ContainerStats,
    ContainerStatus,
    HealthCheck,
    HealthCheckResult,
    HealthStatus,
    NetworkConfig,
    NetworkMode,
    ResourceLimits,
    Snapshot,
)
from gaol.models.profile import Profile, ProfileDependency


class TestContainerConfig:
    """Tests for ContainerConfig model."""

    def test_minimal_config(self) -> None:
        """Test creating a container config with minimal options."""
        config = ContainerConfig(name="test-container")
        assert config.name == "test-container"
        assert config.runtime == "docker"
        assert config.distro == "trixie"
        assert config.profiles == []
        assert config.network.mode == NetworkMode.SHARED

    def test_full_config(self) -> None:
        """Test creating a container config with all options."""
        config = ContainerConfig(
            name="full-container",
            runtime="docker",
            distro="bookworm",
            image="debian:bookworm-slim",
            profiles=["base", "tailscale"],
            network=NetworkConfig(
                mode=NetworkMode.BRIDGED,
                ports={8080: 80, 8443: 443},
                dns=["8.8.8.8", "8.8.4.4"],
                hostname="myhost",
            ),
            resources=ResourceLimits(
                memory_mb=512,
                cpu_count=2.0,
            ),
            volumes={"/data": "/container/data"},
            environment={"DEBUG": "1"},
            working_dir="/app",
            privileged=False,
        )
        assert config.name == "full-container"
        assert config.image == "debian:bookworm-slim"
        assert config.network.mode == NetworkMode.BRIDGED
        assert config.network.ports[8080] == 80
        assert config.resources.memory_mb == 512

    def test_invalid_name(self) -> None:
        """Test that invalid container names are rejected."""
        with pytest.raises(ValidationError):
            ContainerConfig(name="")  # Too short

        with pytest.raises(ValidationError):
            ContainerConfig(name="-invalid")  # Can't start with hyphen

        with pytest.raises(ValidationError):
            ContainerConfig(name="has spaces")  # No spaces allowed


class TestContainerState:
    """Tests for ContainerState model."""

    def test_state_creation(self) -> None:
        """Test creating a container state."""
        state = ContainerState(
            id="abc123",
            name="test-container",
            runtime="docker",
            status=ContainerStatus.RUNNING,
            image="debian:trixie",
        )
        assert state.id == "abc123"
        assert state.status == ContainerStatus.RUNNING
        assert state.ip_address is None

    def test_state_with_network(self) -> None:
        """Test container state with network info."""
        state = ContainerState(
            id="abc123",
            name="test-container",
            runtime="docker",
            status=ContainerStatus.RUNNING,
            image="debian:trixie",
            ip_address="172.17.0.2",
            ports={8080: 80},
        )
        assert state.ip_address == "172.17.0.2"
        assert state.ports[8080] == 80


class TestProfile:
    """Tests for Profile model."""

    def test_minimal_profile(self) -> None:
        """Test creating a minimal profile."""
        profile = Profile(name="test")
        assert profile.name == "test"
        assert profile.packages == []
        assert profile.services == []

    def test_full_profile(self) -> None:
        """Test creating a full profile."""
        profile = Profile(
            name="tailscale",
            description="Tailscale VPN",
            requires_root=True,
            packages=["tailscale"],
            services=["tailscaled"],
            setup_commands=["tailscale up"],
            environment={"TAILSCALE_AUTHKEY": ""},
            exposed_ports=[41641],
        )
        assert profile.requires_root is True
        assert "tailscale" in profile.packages
        assert 41641 in profile.exposed_ports

    def test_profile_from_yaml(self) -> None:
        """Test creating a profile from YAML-like dict."""
        data = {
            "name": "base",
            "description": "Base profile",
            "packages": ["curl", "wget"],
            "depends_on": ["minimal", {"name": "optional-dep", "optional": True}],
        }
        profile = Profile.from_yaml(data)
        assert profile.name == "base"
        assert len(profile.depends_on) == 2
        assert profile.depends_on[0].name == "minimal"
        assert profile.depends_on[0].optional is False
        assert profile.depends_on[1].name == "optional-dep"
        assert profile.depends_on[1].optional is True


class TestProfileDependency:
    """Tests for ProfileDependency model."""

    def test_required_dependency(self) -> None:
        """Test creating a required dependency."""
        dep = ProfileDependency(name="base")
        assert dep.name == "base"
        assert dep.optional is False

    def test_optional_dependency(self) -> None:
        """Test creating an optional dependency."""
        dep = ProfileDependency(name="gui", optional=True)
        assert dep.name == "gui"
        assert dep.optional is True


class TestSnapshot:
    """Tests for Snapshot model."""

    def test_snapshot_creation(self) -> None:
        """Test creating a snapshot."""
        from datetime import datetime

        snapshot = Snapshot(
            id="container1-snap1",
            name="snap1",
            container_id="container1",
            container_name="my-container",
            created_at=datetime.now(),
        )
        assert snapshot.id == "container1-snap1"
        assert snapshot.name == "snap1"
        assert snapshot.container_id == "container1"
        assert snapshot.container_name == "my-container"
        assert snapshot.size_bytes is None
        assert snapshot.description is None

    def test_snapshot_with_all_fields(self) -> None:
        """Test creating a snapshot with all fields."""
        from datetime import datetime

        created = datetime(2024, 1, 15, 10, 30, 0)
        snapshot = Snapshot(
            id="container1-backup",
            name="backup",
            container_id="container1",
            container_name="my-container",
            created_at=created,
            size_bytes=1024 * 1024 * 100,  # 100MB
            description="Pre-upgrade backup",
        )
        assert snapshot.size_bytes == 104857600
        assert snapshot.description == "Pre-upgrade backup"
        assert snapshot.created_at == created


class TestContainerStats:
    """Tests for ContainerStats model."""

    def test_stats_creation(self) -> None:
        """Test creating container stats."""
        stats = ContainerStats(
            container_id="abc123",
            container_name="test-container",
            cpu_percent=25.5,
            cpu_count=4,
            memory_used_bytes=512 * 1024 * 1024,  # 512 MB
            memory_limit_bytes=1024 * 1024 * 1024,  # 1 GB
            memory_percent=50.0,
            network_rx_bytes=1000000,
            network_tx_bytes=500000,
            block_read_bytes=2000000,
            block_write_bytes=1000000,
            pids=10,
        )
        assert stats.container_id == "abc123"
        assert stats.cpu_percent == 25.5
        assert stats.memory_used_mb == 512.0
        assert stats.memory_limit_mb == 1024.0
        assert stats.pids == 10

    def test_stats_defaults(self) -> None:
        """Test container stats defaults."""
        stats = ContainerStats(
            container_id="abc123",
            container_name="test-container",
        )
        assert stats.cpu_percent == 0.0
        assert stats.memory_used_bytes == 0
        assert stats.memory_limit_bytes is None
        assert stats.memory_limit_mb is None
        assert stats.network_rx_bytes == 0
        assert stats.pids == 0


class TestHealthCheck:
    """Tests for HealthCheck model."""

    def test_health_check_creation(self) -> None:
        """Test creating a health check."""
        check = HealthCheck(
            command=["curl", "-f", "http://localhost/health"],
            interval_seconds=30,
            timeout_seconds=10,
            retries=3,
        )
        assert check.command == ["curl", "-f", "http://localhost/health"]
        assert check.interval_seconds == 30
        assert check.timeout_seconds == 10
        assert check.retries == 3
        assert check.start_period_seconds == 0

    def test_health_check_defaults(self) -> None:
        """Test health check defaults."""
        check = HealthCheck(command=["true"])
        assert check.interval_seconds == 30
        assert check.timeout_seconds == 10
        assert check.retries == 3
        assert check.start_period_seconds == 0


class TestHealthCheckResult:
    """Tests for HealthCheckResult model."""

    def test_healthy_result(self) -> None:
        """Test healthy check result."""
        result = HealthCheckResult(
            status=HealthStatus.HEALTHY,
            exit_code=0,
            output="OK",
        )
        assert result.status == HealthStatus.HEALTHY
        assert result.exit_code == 0
        assert result.consecutive_failures == 0

    def test_unhealthy_result(self) -> None:
        """Test unhealthy check result."""
        result = HealthCheckResult(
            status=HealthStatus.UNHEALTHY,
            exit_code=1,
            output="Connection refused",
            consecutive_failures=3,
        )
        assert result.status == HealthStatus.UNHEALTHY
        assert result.exit_code == 1
        assert result.consecutive_failures == 3

    def test_health_status_values(self) -> None:
        """Test health status enum values."""
        assert HealthStatus.HEALTHY.value == "healthy"
        assert HealthStatus.UNHEALTHY.value == "unhealthy"
        assert HealthStatus.STARTING.value == "starting"
        assert HealthStatus.UNKNOWN.value == "unknown"
