"""Tests for subnet allocator."""

from pathlib import Path

import pytest

from gaol.networking.allocator import (
    allocate,
    get_allocation,
    list_allocations,
    release,
    to_veth_config,
)


@pytest.fixture
def state_file(tmp_path: Path) -> Path:
    """Temporary state file for testing."""
    return tmp_path / "subnet-allocations.yaml"


class TestAllocate:
    def test_first_allocation(self, state_file: Path):
        alloc = allocate("research", state_path=state_file)
        assert alloc.container_name == "research"
        assert alloc.subnet == "10.200.1.0/30"
        assert alloc.host_ip == "10.200.1.1"
        assert alloc.container_ip == "10.200.1.2"
        assert alloc.host_iface == "ve-research"
        assert alloc.table_id == 200
        assert alloc.priority == 100

    def test_sequential_allocations(self, state_file: Path):
        a1 = allocate("research", state_path=state_file)
        a2 = allocate("crypto", state_path=state_file)
        assert a1.subnet == "10.200.1.0/30"
        assert a2.subnet == "10.200.2.0/30"
        assert a1.table_id == 200
        assert a2.table_id == 201
        assert a1.priority == 100
        assert a2.priority == 101

    def test_idempotent_allocation(self, state_file: Path):
        a1 = allocate("research", state_path=state_file)
        a2 = allocate("research", state_path=state_file)
        assert a1 == a2

    def test_custom_iface(self, state_file: Path):
        alloc = allocate("mycontainer", host_iface="ve-custom", state_path=state_file)
        assert alloc.host_iface == "ve-custom"

    def test_persists_to_disk(self, state_file: Path):
        allocate("research", state_path=state_file)
        assert state_file.exists()
        # Load again from disk
        alloc = get_allocation("research", state_path=state_file)
        assert alloc is not None
        assert alloc.subnet == "10.200.1.0/30"

    def test_survives_reload(self, state_file: Path):
        allocate("first", state_path=state_file)
        allocate("second", state_path=state_file)
        # Allocate a third — should continue from where we left off
        a3 = allocate("third", state_path=state_file)
        assert a3.subnet == "10.200.3.0/30"
        assert a3.table_id == 202


class TestRelease:
    def test_release_existing(self, state_file: Path):
        allocate("research", state_path=state_file)
        assert release("research", state_path=state_file) is True
        assert get_allocation("research", state_path=state_file) is None

    def test_release_nonexistent(self, state_file: Path):
        assert release("nonexistent", state_path=state_file) is False

    def test_release_allows_reuse(self, state_file: Path):
        allocate("research", state_path=state_file)
        release("research", state_path=state_file)
        # New allocation gets next available octet (doesn't reuse)
        a2 = allocate("newcontainer", state_path=state_file)
        # The octet counter advances, but the released slot is skippable
        assert a2.container_name == "newcontainer"


class TestListAllocations:
    def test_empty(self, state_file: Path):
        assert list_allocations(state_path=state_file) == []

    def test_lists_all(self, state_file: Path):
        allocate("a", state_path=state_file)
        allocate("b", state_path=state_file)
        allocs = list_allocations(state_path=state_file)
        names = [a.container_name for a in allocs]
        assert "a" in names
        assert "b" in names


class TestToVethConfig:
    def test_converts_correctly(self, state_file: Path):
        alloc = allocate("research", state_path=state_file)
        veth = to_veth_config(alloc)
        assert veth.host_iface == "ve-research"
        assert veth.container_ip == "10.200.1.2"
        assert veth.host_ip == "10.200.1.1"
        assert veth.subnet == "10.200.1.0/30"
