"""Contract: every wire `Err` code maps to a typed Python exception.

The EH-02 (federation) discipline: NO untyped exceptions cross the
SDK seam. A wire `err: "Conflict"` MUST surface as `ConflictError`,
never as a bare `MgfHrbError`. If a future broker adds a new `Err`
variant without registering a Python class, this test catches it.

The map is `from_wire(err_str) -> MgfHrbError` in
`mgf/hrb/exceptions.py`.
"""

from __future__ import annotations

import pytest

from mgf.hrb import (
    BadRequestError,
    ConflictError,
    HardwareFaultError,
    InvalidTokenError,
    MgfHrbError,
    NotFoundError,
    NotPermittedError,
    OverloadedError,
    RevokedError,
    TimeoutError,
    UnavailableError,
    UnsupportedError,
)
from mgf.hrb.exceptions import from_wire

pytestmark = pytest.mark.contract


# The full mapping the broker can emit. Mirror of `model.zig`'s
# `Err` enum — when that enum grows a variant, this list grows too,
# in the same commit.
_WIRE_TO_PYTHON = {
    "NotFound": NotFoundError,
    "NotPermitted": NotPermittedError,
    "Conflict": ConflictError,
    "Unsupported": UnsupportedError,
    "HardwareFault": HardwareFaultError,
    "InvalidToken": InvalidTokenError,
    "BadRequest": BadRequestError,
    "Timeout": TimeoutError,
    "Overloaded": OverloadedError,
    "Revoked": RevokedError,
    "Unavailable": UnavailableError,
}


@pytest.mark.parametrize("wire_code,expected_cls", list(_WIRE_TO_PYTHON.items()))
def test_every_wire_err_maps_to_typed_python_exception(
    wire_code: str, expected_cls: type[MgfHrbError]
) -> None:
    """One test per (wire_code, expected_class) pair. Parametrized so
    a new wire variant becoming registered shows up as a new test row
    — easy to read in CI output."""
    exc = from_wire(wire_code)
    assert isinstance(exc, expected_cls), (
        f"wire `{wire_code}` mapped to {type(exc).__name__}, expected {expected_cls.__name__}"
    )


def test_every_mapped_exception_subclasses_mgf_hrb_error() -> None:
    """EH-01 root: every exception in the map descends from
    `MgfHrbError`. A consumer doing `except MgfHrbError:` catches
    ALL broker failures, never just some."""
    for wire_code, cls in _WIRE_TO_PYTHON.items():
        assert issubclass(cls, MgfHrbError), (
            f"{cls.__name__} (wire `{wire_code}`) doesn't descend from "
            f"MgfHrbError — EH-01 violation"
        )


def test_unknown_wire_code_falls_back_to_root() -> None:
    """A wire variant the SDK doesn't recognize falls back to
    `MgfHrbError` (not a KeyError). Lets the SDK keep working
    against a newer broker that grew an unknown Err variant —
    consumers still get a typed error, just less-specific."""
    exc = from_wire("some_future_variant_we_dont_know_yet")
    assert isinstance(exc, MgfHrbError)
    # The error message preserves the wire string so a human can
    # diagnose what the unknown variant was.
    assert "some_future_variant_we_dont_know_yet" in str(exc)
