"""Tests for the OPTIONAL guest-agent surface (Wave-R6, D-G19).

Covers the neutral value types (:class:`GuestNic` / :class:`GuestOsInfo`) and
the :class:`FakeGuestAgentBackend` read semantics: reachable vs unreachable,
seeded reports, ``DomainNotFound`` for unknown domains.
"""

from __future__ import annotations

import dataclasses

import pytest

from mgf.vm.core.contracts import GuestAgentBackend, GuestNic, GuestOsInfo
from mgf.vm.core.exceptions import DomainNotFound, GuestUnreachableError
from mgf.vm.core.fakes import FakeGuestAgentBackend
from mgf.vm.core.ids import DomainId


class TestGuestValueTypes:
    def test_guest_nic_defaults(self) -> None:
        nic = GuestNic(name="eth0")
        assert nic.mac is None
        assert nic.ip_addresses == ()

    def test_guest_nic_is_frozen(self) -> None:
        nic = GuestNic(name="eth0")
        with pytest.raises(dataclasses.FrozenInstanceError):
            nic.name = "ens3"  # type: ignore[misc]

    def test_guest_os_info_defaults_empty(self) -> None:
        info = GuestOsInfo()
        assert info.id == ""
        assert info.name == ""
        assert info.version == ""
        assert info.pretty_name == ""


class TestFakeGuestAgentBackend:
    def test_satisfies_protocol(self) -> None:
        # runtime_checkable Protocol membership (the optional-backend contract).
        assert isinstance(FakeGuestAgentBackend(), GuestAgentBackend)

    def test_unknown_domain_raises_domain_not_found(self) -> None:
        backend = FakeGuestAgentBackend()
        d = DomainId("ghost")
        with pytest.raises(DomainNotFound):
            backend.guest_ping(d)
        with pytest.raises(DomainNotFound):
            backend.guest_os_info(d)
        with pytest.raises(DomainNotFound):
            backend.guest_interfaces(d)

    def test_known_reachable_domain_reports_seeded_state(self) -> None:
        d = DomainId("vm-1")
        backend = FakeGuestAgentBackend(known_domains=[d])
        backend._set_os_info(d, GuestOsInfo(id="ubuntu", pretty_name="Ubuntu 24.04"))
        backend._set_interfaces(
            d, (GuestNic(name="enp1s0", mac="52:54:00:aa:bb:cc", ip_addresses=("10.0.0.5",)),)
        )

        assert backend.guest_ping(d) is True
        assert backend.guest_os_info(d).id == "ubuntu"
        nics = backend.guest_interfaces(d)
        assert nics[0].ip_addresses == ("10.0.0.5",)

    def test_unreachable_domain(self) -> None:
        d = DomainId("vm-2")
        backend = FakeGuestAgentBackend(known_domains=[d])
        backend._set_reachable(d, reachable=False)

        # ping does not raise — it reports the agent as down.
        assert backend.guest_ping(d) is False
        with pytest.raises(GuestUnreachableError):
            backend.guest_os_info(d)
        with pytest.raises(GuestUnreachableError):
            backend.guest_interfaces(d)

    def test_register_domain_helper(self) -> None:
        backend = FakeGuestAgentBackend()
        d = DomainId("late")
        backend._register_domain(d)
        assert backend.guest_ping(d) is True
        assert backend.guest_interfaces(d) == ()

    def test_close_is_idempotent(self) -> None:
        backend = FakeGuestAgentBackend()
        assert backend.closed is False
        backend.close()
        backend.close()
        assert backend.closed is True
