"""Tier-1 tests for :class:`LibvirtDomainPolicyBackend` (D-G25).

No real libvirt: a self-contained fake ``virConnect`` / ``virDomain`` exercises
get/set autostart + managed-save and the seam's not-found normalisation.
"""

from __future__ import annotations

from typing import TYPE_CHECKING

import pytest
from mgf.vm.core.exceptions import DomainNotFound
from mgf.vm.core.ids import DomainId

from mgf.vm.libvirt._connection import LibvirtConnection
from mgf.vm.libvirt._domain_policy import LibvirtDomainPolicyBackend

if TYPE_CHECKING:
    from collections.abc import Callable, Iterator

_UUID = "11111111-2222-3333-4444-555555555555"


class _FakeLibvirtError(Exception):
    pass


class _FakeDomain:
    def __init__(self, *, running: bool, autostart: int = 0) -> None:
        self._running = running
        self._autostart = autostart
        self.managed_saved = False

    def autostart(self) -> int:
        return self._autostart

    def setAutostart(self, flag: int) -> None:  # noqa: N802
        self._autostart = flag

    def managedSave(self, _flags: int) -> None:  # noqa: N802
        if not self._running:
            raise _FakeLibvirtError("domain is not running")
        self.managed_saved = True
        self._running = False


class _FakeConn:
    def __init__(self, dom: _FakeDomain | None) -> None:
        self._dom = dom

    def lookupByUUIDString(self, _uuid: str) -> _FakeDomain:  # noqa: N802
        if self._dom is None:
            raise _FakeLibvirtError("no such domain")
        return self._dom

    def close(self) -> int:
        return 0


@pytest.fixture
def make_backend() -> Iterator[Callable[[_FakeDomain | None], LibvirtDomainPolicyBackend]]:
    """Build a backend over an adopted fake connection, closing it after the
    test so ``LibvirtConnection``'s DP-13 not-closed ResourceWarning never fires."""
    conns: list[LibvirtConnection] = []

    def _make(dom: _FakeDomain | None) -> LibvirtDomainPolicyBackend:
        wrapped = LibvirtConnection.adopt(_FakeConn(dom), uri="test:///unit")
        conns.append(wrapped)
        return LibvirtDomainPolicyBackend(wrapped)

    yield _make
    for c in conns:
        c.close()


def test_get_autostart_reads_flag(make_backend: Callable[..., LibvirtDomainPolicyBackend]) -> None:
    be = make_backend(_FakeDomain(running=False, autostart=1))
    assert be.get_autostart(DomainId(_UUID)) is True


def test_set_then_get_autostart_round_trips(
    make_backend: Callable[..., LibvirtDomainPolicyBackend],
) -> None:
    dom = _FakeDomain(running=False, autostart=0)
    be = make_backend(dom)
    be.set_autostart(DomainId(_UUID), enabled=True)
    assert dom.autostart() == 1
    be.set_autostart(DomainId(_UUID), enabled=False)
    assert dom.autostart() == 0


def test_managed_save_running_domain(
    make_backend: Callable[..., LibvirtDomainPolicyBackend],
) -> None:
    dom = _FakeDomain(running=True)
    be = make_backend(dom)
    be.managed_save(DomainId(_UUID))
    assert dom.managed_saved is True


def test_managed_save_stopped_domain_raises(
    make_backend: Callable[..., LibvirtDomainPolicyBackend],
) -> None:
    be = make_backend(_FakeDomain(running=False))
    with pytest.raises(Exception):  # noqa: B017 — seam-translated libvirtError
        be.managed_save(DomainId(_UUID))


def test_unknown_domain_raises_domain_not_found(
    make_backend: Callable[..., LibvirtDomainPolicyBackend],
) -> None:
    be = make_backend(None)
    with pytest.raises(DomainNotFound):
        be.get_autostart(DomainId(_UUID))


def test_backend_is_noop_context_manager(
    make_backend: Callable[..., LibvirtDomainPolicyBackend],
) -> None:
    be = make_backend(_FakeDomain(running=False))
    with be as ctx:
        assert ctx is be
