"""PC-06: ``ExceptionTranslationMiddleware._lookup_status`` MRO walk cost.

Baseline-relative (PF-01). The middleware only runs on exception (the happy
path costs nothing). But when an exception fires, ``_lookup_status`` walks
``exc_type.__mro__`` checking ``self._status_map``. Per call: O(MRO depth x map
size).

For a deeply-derived exception (e.g., a 5-level inheritance chain from
AppError) against a 20-entry status_map, that's ~100 dict lookups worst case.
Sub-µs per dict op in CPython; the worst case is still microseconds — but PROD
apps can have 100s of req/s on the exception path during an incident.

Pinned: lookup against a 5-level deep AppError subclass on a 20-entry map,
compared to the recorded baseline in ``baselines.json`` (PF-01/07) — NOT the
old absolute 20 µs budget. A regression usually means the lookup acquired a
per-call expense (logging, allocation, an isinstance chain instead of a dict
lookup).

Marker: ``perf``. Run via ``pytest -m perf``.
"""

from __future__ import annotations

from typing import TYPE_CHECKING

import pytest
from mgf.common.exceptions import AppError

from mgf.fastapi._exceptions import ExceptionTranslationMiddleware

if TYPE_CHECKING:
    from tests.perf.conftest import Baselines, _Bench

pytestmark = pytest.mark.perf


def test_lookup_status_no_regression(bench: _Bench, baselines: Baselines) -> None:
    # Build a deep AppError subclass hierarchy.
    class L1Error(AppError):
        pass

    class L2Error(L1Error):
        pass

    class L3Error(L2Error):
        pass

    class L4Error(L3Error):
        pass

    class L5Error(L4Error):
        pass

    # 20-entry status_map (none matching L5Error directly — forces a full MRO
    # walk down to AppError).
    status_map: dict[type[AppError], int] = {
        type(f"Unrelated{i}Error", (AppError,), {}): 400 + i for i in range(19)
    }
    status_map[AppError] = 500

    # Construct middleware (the app arg is unused for _lookup_status).
    middleware = ExceptionTranslationMiddleware(
        app=None,  # type: ignore[arg-type]
        status_map=status_map,
    )

    per_call_us = (
        bench.measure(lambda: middleware._lookup_status(L5Error), iterations=10_000, warmup=100)
        * 1e6
    )
    baselines.assert_no_regression(
        "exception_lookup_p50_us",
        per_call_us,
        units="us",
        description=(
            "ExceptionTranslationMiddleware._lookup_status MRO walk, 5-level AppError subclass "
            "on a 20-entry map, median over 10k"
        ),
    )
