"""Real-engine live event delivery for ``watch_events`` (D-G17).

Proves the shared :class:`~mgf.vm.libvirt._event_pump.LibvirtEventPump`
actually delivers a libvirt lifecycle event end-to-end on the
``test:///default`` driver: define a domain, subscribe, start it, and
assert a live ``VmEvent`` arrives through the pump's
``virEventRunDefaultImpl`` loop.

Marked ``@pytest.mark.conformance`` (Tier 2). SKIPPED gracefully if no
libvirt engine is reachable.
"""

from __future__ import annotations

import threading
from typing import TYPE_CHECKING

import pytest

if TYPE_CHECKING:
    from collections.abc import Iterator

pytestmark = pytest.mark.conformance

_URI = "test:///default"


def _open_backend() -> object:
    try:
        import libvirt
    except ImportError:
        pytest.skip("libvirt-python not installed")
    try:
        conn = libvirt.open(_URI)
    except Exception as exc:  # any open failure → skip gracefully
        pytest.skip(f"cannot open {_URI!r}: {exc}")
    if conn is None:
        pytest.skip(f"libvirt.open({_URI!r}) returned None")
    conn.close()

    from mgf.vm.libvirt import LibvirtHypervisorBackend

    return LibvirtHypervisorBackend(_URI)


@pytest.fixture
def backend() -> Iterator[object]:
    be = _open_backend()
    try:
        yield be
    finally:
        be.close()  # type: ignore[attr-defined]


def test_watch_events_delivers_live_lifecycle_event(backend: object) -> None:
    from mgf.vm.core.contracts import VmEvent, VmSpec

    spec = VmSpec(name="dg17-live-evt", cpu=1, memory_bytes=64 * 1024 * 1024)
    domain_id = backend.define(spec)  # type: ignore[attr-defined]

    stream = backend.watch_events(domain_id)  # type: ignore[attr-defined]
    live = threading.Event()
    captured: list[object] = []

    def _reader() -> None:
        for event in stream:
            captured.append(event)
            if isinstance(event, VmEvent) and event.payload.get("event") == "lifecycle":
                live.set()
                return

    reader = threading.Thread(target=_reader, daemon=True)
    reader.start()
    try:
        # Give the reader a beat to drain the primed current-state events
        # and block on the live queue, then trigger a real transition.
        live.wait(timeout=1.0)
        backend.start(domain_id)  # type: ignore[attr-defined]
        assert live.wait(timeout=10.0), "no live lifecycle event delivered"
        lifecycle = [
            e for e in captured if isinstance(e, VmEvent) and e.payload.get("event") == "lifecycle"
        ]
        assert lifecycle, "expected at least one live lifecycle VmEvent"
    finally:
        stream.close()
        reader.join(timeout=2.0)
        try:
            backend.stop(domain_id, force=True)  # type: ignore[attr-defined]
        except Exception:  # noqa: S110 - best-effort cleanup
            pass
        try:
            backend.undefine(domain_id)  # type: ignore[attr-defined]
        except Exception:  # noqa: S110 - best-effort cleanup
            pass
