"""Coverage gap tests for fabric/regulatory_export.py — lines 94-97, 137-138."""

from __future__ import annotations

import types

import pytest

from orxaq.fabric.regulatory_export import (
    build_regulatory_package,
)


def _make_cecl(segments=None, ecl=1000.0, pd=0.05, lgd=0.45, ead=20000.0):
    if segments is None:
        segments = {
            "Retail": {"ead": 10000.0, "pd": 0.04, "lgd": 0.45, "ecl": 400.0},
            "Corp": {"ead": 10000.0, "pd": 0.06, "lgd": 0.45, "ecl": 600.0},
        }
    return types.SimpleNamespace(segments=segments, ecl=ecl, pd=pd, lgd=lgd, ead=ead)


def _make_stress(quarterly_ecl=None, confidence_intervals=None):
    if quarterly_ecl is None:
        quarterly_ecl = [100.0 * (i + 1) for i in range(9)]
    if confidence_intervals is None:
        confidence_intervals = [(q * 0.9, q * 1.1) for q in quarterly_ecl]
    return types.SimpleNamespace(
        quarterly_ecl=quarterly_ecl,
        confidence_intervals=confidence_intervals,
    )


class TestSegmentECLFloatPath:
    """Lines 94-97: when seg_data is a plain float (not dict)."""

    def test_segment_as_float_value(self) -> None:
        """ECL segments can be raw floats — should produce valid schedule rows."""
        cecl = _make_cecl(
            segments={"Retail": 500.0, "Corp": 300.0},
            ecl=800.0,
            pd=0.05,
            lgd=0.45,
            ead=16000.0,
        )
        stress = {
            "baseline": _make_stress(),
            "adverse": _make_stress([100.0] * 9),
            "severely_adverse": _make_stress([200.0] * 9),
        }
        pkg = build_regulatory_package(
            cecl_result=cecl,
            stress_reports=stress,
            as_of_date="2025-12-31",
            institution_id="FLOATTEST",
            submission_period="2025Q4",
        )
        assert len(pkg.schedule_h1) > 0
        # All rows must have numeric ead/pd/lgd/ecl
        for row in pkg.schedule_h1:
            assert isinstance(row["ead"], float)
            assert isinstance(row["ecl"], float)

    def test_mixed_segment_dict_and_float(self) -> None:
        """One dict segment + one float segment in same run."""
        cecl = _make_cecl(
            segments={
                "DictSeg": {"ead": 12000.0, "pd": 0.04, "lgd": 0.44, "ecl": 210.0},
                "FloatSeg": 390.0,
            },
            ecl=600.0,
            pd=0.04,
            lgd=0.44,
            ead=12000.0,
        )
        stress = {
            "baseline": _make_stress(),
            "adverse": _make_stress([80.0] * 9),
            "severely_adverse": _make_stress([160.0] * 9),
        }
        pkg = build_regulatory_package(
            cecl_result=cecl,
            stress_reports=stress,
            as_of_date="2026-03-31",
            institution_id="MIXED001",
            submission_period="2026Q1",
        )
        assert len(pkg.schedule_h1) == 2


class TestCCARProjectionDictCI:
    """Lines 137-138: confidence_intervals is a dict → broadcast total_ecl CI."""

    def test_dict_confidence_intervals_broadcast(self) -> None:
        """When stress.confidence_intervals is a dict, total_ecl CI is broadcast."""
        stress_dict_ci = types.SimpleNamespace(
            quarterly_ecl=[100.0 * (i + 1) for i in range(9)],
            confidence_intervals={"total_ecl": (800.0, 1200.0), "extra": (0.0, 1.0)},
        )
        cecl = _make_cecl()
        stress_reports = {
            "baseline": stress_dict_ci,
            "adverse": stress_dict_ci,
            "severely_adverse": stress_dict_ci,
        }
        pkg = build_regulatory_package(
            cecl_result=cecl,
            stress_reports=stress_reports,
            as_of_date="2025-12-31",
            institution_id="DICTCI001",
            submission_period="2025Q4",
        )
        assert len(pkg.ccar_projection) == 9
        # Each quarter's CI should be the broadcast tuple
        for row in pkg.ccar_projection:
            lo, hi = row["ci_lower"], row["ci_upper"]
            assert lo == pytest.approx(800.0)
            assert hi == pytest.approx(1200.0)
