"""Cross-SIP PE_DMA routing tests (ADR-0023, topology v2).

Verifies that PE_DMA in one SIP can route to PE_DMA in another SIP via
the bidirectional pcie_ep ↔ fabric.switch0 path. Required for IPCQ
multi-SIP collectives.
"""
from __future__ import annotations

import pytest

from kernbench.policy.routing.router import PathRouter, RoutingError
from kernbench.topology.builder import resolve_topology


def _topo():
    return resolve_topology("topology.yaml").topology_obj


# ── New edge ────────────────────────────────────────────────────────


def test_pcie_ep_to_switch_edge_exists():
    """The reverse pcie_ep → switch edge must exist for outbound traffic."""
    topo = _topo()
    pairs = {(e.src, e.dst) for e in topo.edges}
    assert ("sip0.io0.pcie_ep", "fabric.switch0") in pairs
    assert ("sip1.io0.pcie_ep", "fabric.switch0") in pairs


def test_existing_switch_to_pcie_ep_still_present():
    """Host→device path must remain intact (regression)."""
    topo = _topo()
    pairs = {(e.src, e.dst) for e in topo.edges}
    assert ("fabric.switch0", "sip0.io0.pcie_ep") in pairs
    assert ("fabric.switch0", "sip1.io0.pcie_ep") in pairs


# ── Cross-SIP path ──────────────────────────────────────────────────


def test_router_finds_cross_sip_pe_dma_path():
    topo = _topo()
    r = PathRouter(topo)
    path = r.find_path("sip0.cube0.pe0", "sip1.cube0.pe0.pe_dma")
    assert len(path) > 0
    assert path[0] == "sip0.cube0.pe0.pe_dma"
    assert path[-1] == "sip1.cube0.pe0.pe_dma"
    assert "fabric.switch0" in path


def test_router_finds_cross_sip_far_pe_path():
    """Last cube of sip0 → first cube of sip1."""
    topo = _topo()
    r = PathRouter(topo)
    path = r.find_path("sip0.cube15.pe7", "sip1.cube0.pe0.pe_dma")
    assert "fabric.switch0" in path


# ── Regression: intra-SIP routing unchanged ─────────────────────────


def test_router_intra_sip_path_unchanged():
    topo = _topo()
    r = PathRouter(topo)
    path = r.find_path("sip0.cube0.pe0", "sip0.cube0.pe1.pe_dma")
    assert "fabric.switch0" not in path  # should not detour through switch


def test_router_intra_cube_path_unchanged():
    topo = _topo()
    r = PathRouter(topo)
    path = r.find_path("sip0.cube0.pe0", "sip0.cube0.hbm_ctrl.pe0")
    assert "fabric.switch0" not in path
