"""Shared pytest fixtures for the kernbench test suite.

Session-scoped topology caching: ``resolve_topology("topology.yaml")`` is
pure (no side effects), so we cache the result across all tests in a
worker process. Each test still builds its own ``GraphEngine`` (which is
stateful/SimPy-event-consuming and MUST NOT be shared).
"""
from __future__ import annotations

import os

import pytest

from kernbench.topology.builder import resolve_topology


def pytest_sessionfinish(session, exitstatus):
    """Aggregate parametrized sweep rows into combined CSV + PNG plots.

    Runs on the controller node only (xdist worker processes set
    ``PYTEST_XDIST_WORKER``; we skip those). Idempotent — does nothing
    if no sweep rows are present (e.g., when the sweep was filtered out).
    """
    if os.environ.get("PYTEST_XDIST_WORKER"):
        return
    import importlib.util
    import sys
    from pathlib import Path

    def _exec(name: str, attr: str) -> None:
        mod_path = Path(__file__).parent / name
        if not mod_path.exists():
            return
        s = importlib.util.spec_from_file_location(
            f"_{name.removesuffix('.py')}_for_aggregate", mod_path,
        )
        if s is None or s.loader is None:
            return
        mod = importlib.util.module_from_spec(s)
        sys.modules[s.name] = mod
        try:
            s.loader.exec_module(mod)
            fn = getattr(mod, attr, None)
            if fn is not None:
                fn()
        except Exception as e:
            print(f"[conftest] aggregator {attr}() in {name} failed: {e}")

    _exec("sccl/_allreduce_helpers.py", "_aggregate_sweep_plots")
    _exec("sccl/_allreduce_helpers.py", "aggregate_buffer_kind_plot")


@pytest.fixture(scope="session")
def topology():
    """Session-scoped parsed topology (immutable graph + spec).

    Usage in tests::

        def test_foo(topology):
            engine = GraphEngine(topology.topology_obj, enable_data=True)
    """
    return resolve_topology("topology.yaml")


@pytest.fixture(scope="session")
def topology_obj(topology):
    """The TopologyGraph inside the handle (convenience shortcut)."""
    return topology.topology_obj


@pytest.fixture(scope="session")
def spec(topology):
    """Topology spec dict (convenience shortcut)."""
    return topology.topology_obj.spec
