"""Real-engine conformance for ``LibvirtStorageBackend`` (CONF-S-*).

Drives the core conformance suite from ``mgf.vm.core.conformance`` against a
live ``LibvirtStorageBackend`` bound to ``qemu:///session``. Per
``contracts.md`` §10 these are real-engine only (no mocks).

Scenarios exercised here:

* **CONF-S-01** — create → list → delete a volume round-trip.
* **CONF-S-03** — a volume with derived snapshots refuses delete.

Both are capability-gated and SKIP gracefully when ``libvirt.open`` raises
(no libvirtd / no session bus) or when ``qemu-img`` is unavailable. The
fixture creates + activates a **transient** dir pool named ``default`` in a
temp directory (``test:///default`` lacks persistent pools, so we drive
``qemu:///session`` which the conformance helpers target via the literal
pool name ``"default"``).
"""

from __future__ import annotations

import shutil
import uuid
from typing import TYPE_CHECKING

import pytest
from mgf.vm.core.conformance import storage_conformance_suite
from mgf.vm.core.contracts import PoolSpec

from mgf.vm.libvirt._storage import LibvirtStorageBackend

if TYPE_CHECKING:
    from collections.abc import Iterator
    from pathlib import Path

pytestmark = pytest.mark.conformance

_SESSION_URI = "qemu:///session"
_POOL_NAME = "default"


def _open_backend() -> LibvirtStorageBackend | None:
    """Open a storage backend on the session URI, or ``None`` to skip."""
    try:
        import libvirt
    except ImportError:
        return None
    try:
        conn = libvirt.open(_SESSION_URI)
    except libvirt.libvirtError:
        return None
    if conn is None:
        return None
    conn.close()
    return LibvirtStorageBackend.open(_SESSION_URI)


@pytest.fixture
def storage_backend(tmp_path: Path) -> Iterator[LibvirtStorageBackend]:
    """A live backend with a transient ``default`` dir pool the suite uses."""
    if shutil.which("qemu-img") is None:
        pytest.skip("qemu-img not available")
    backend = _open_backend()
    if backend is None:
        pytest.skip(f"cannot open {_SESSION_URI} (no libvirtd / session bus)")

    # A unique target dir so parallel runs / leftovers never collide. The pool
    # is named "default" because the core storage scenarios hard-code that pool
    # name (mgf.vm.core.conformance.storage._volume_spec).
    target = tmp_path / f"pool-{uuid.uuid4().hex[:8]}"
    target.mkdir(parents=True, exist_ok=True)
    created_pool = False
    try:
        try:
            backend.get_pool(_POOL_NAME)
        except Exception:
            backend.create_pool(
                PoolSpec(
                    name=_POOL_NAME,
                    pool_type="dir",
                    target_path=str(target),
                )
            )
            created_pool = True
        yield backend
    finally:
        # Best-effort teardown: drop our pool (force-cascades volumes) only if
        # we created it, then close the connection deterministically (DP-13).
        try:
            if created_pool:
                backend.delete_pool(_POOL_NAME, force=True)
        except Exception:  # noqa: S110 - teardown is best-effort
            pass
        backend.close()


def test_capabilities_report_real_engine(
    storage_backend: LibvirtStorageBackend,
) -> None:
    """Sanity: the live backend reports qcow2 + dir support (gates the suite)."""
    caps = storage_backend.capabilities()
    assert "qcow2" in caps.supports_formats
    assert "dir" in caps.supports_pool_types


def test_conf_s_01_create_list_delete(
    storage_backend: LibvirtStorageBackend,
) -> None:
    """CONF-S-01 — create-list-delete volume round-trip (real engine)."""
    suite = storage_conformance_suite(storage_backend)
    result = suite.run_one("CONF-S-01")
    if result.error is not None:
        raise result.error
    assert result.passed


def test_conf_s_03_volume_with_snapshots_refuses_delete(
    storage_backend: LibvirtStorageBackend,
) -> None:
    """CONF-S-03 — a volume with snapshots cannot be deleted (real engine)."""
    suite = storage_conformance_suite(storage_backend)
    result = suite.run_one("CONF-S-03")
    if result.error is not None:
        raise result.error
    assert result.passed
