"""Wave-R3 unit tests — network management through the SDK (D-G15).

Drives ``VmManagerClient`` over ``InProcessTransport`` with the core
``FakeNetworkBackend`` (writing through to a ``FakeHypervisorBackend`` so the
client's ``list_networks`` observes the effects) and asserts the
define/start/stop/delete surface + the typed-error contract (no backend ->
``TransportError``; unknown network -> ``NetworkNotFound``).
"""

from __future__ import annotations

import pytest
from mgf.vm.core.contracts import NetworkProfile, NetworkSpec
from mgf.vm.core.exceptions import NetworkNotFound, TransportError
from mgf.vm.core.fakes import FakeHypervisorBackend, FakeNetworkBackend

from mgf.vm.sdk.client import VmManagerClient
from mgf.vm.sdk.transport.inprocess import InProcessTransport


def _client(*, with_network: bool = True) -> tuple[VmManagerClient, FakeHypervisorBackend]:
    hv = FakeHypervisorBackend()
    network = FakeNetworkBackend(hv) if with_network else None
    transport = InProcessTransport.from_adapters(hv, network=network)
    return VmManagerClient(transport), hv


def _spec(name: str = "lab-net") -> NetworkSpec:
    return NetworkSpec(name=name, forward_mode="nat", cidr="192.168.80.0/24")


def test_define_returns_profile_and_is_observable() -> None:
    client, _hv = _client()
    profile = client.define_network(_spec())
    assert isinstance(profile, NetworkProfile)
    assert profile.name == "lab-net"
    assert profile.active is False
    assert "lab-net" in {n.name for n in client.list_networks()}


def test_start_then_stop_toggles_observed_active() -> None:
    client, _hv = _client()
    client.define_network(_spec())
    client.start_network("lab-net")
    assert next(n for n in client.list_networks() if n.name == "lab-net").active is True
    client.stop_network("lab-net")
    assert next(n for n in client.list_networks() if n.name == "lab-net").active is False


def test_delete_removes_and_is_idempotent() -> None:
    client, _hv = _client()
    client.define_network(_spec())
    client.delete_network("lab-net")
    assert "lab-net" not in {n.name for n in client.list_networks()}
    client.delete_network("lab-net")  # idempotent — no raise


def test_start_unknown_raises_network_not_found() -> None:
    client, _hv = _client()
    with pytest.raises(NetworkNotFound):
        client.start_network("ghost")


def test_define_without_backend_raises_transport_error() -> None:
    client, _hv = _client(with_network=False)
    with pytest.raises(TransportError, match="NetworkBackend"):
        client.define_network(_spec())


def test_start_without_backend_raises_transport_error() -> None:
    client, _hv = _client(with_network=False)
    with pytest.raises(TransportError, match="NetworkBackend"):
        client.start_network("lab-net")
