"""Credit risk reporting — structured report generation.

Combines portfolio analytics, CECL, stress testing, and fair lending
results into a unified risk report with narrative summaries and
risk ratings. Stdlib-only per ADR-007.
"""

from __future__ import annotations

import uuid
from dataclasses import dataclass
from datetime import UTC, datetime


@dataclass(frozen=True)
class ReportSection:
    """Single section of a risk report."""

    title: str
    metrics: dict[str, float]
    narrative: str


@dataclass
class RiskReport:
    """Complete credit risk report."""

    report_id: str
    generated_at: str
    sections: list[ReportSection]
    summary: str
    risk_rating: str  # "low", "moderate", "high", "critical"

    def to_dict(self) -> dict:
        """Serialize to dictionary for JSON output."""
        return {
            "report_id": self.report_id,
            "generated_at": self.generated_at,
            "risk_rating": self.risk_rating,
            "summary": self.summary,
            "sections": [
                {
                    "title": s.title,
                    "metrics": s.metrics,
                    "narrative": s.narrative,
                }
                for s in self.sections
            ],
        }

    def to_text(self) -> str:
        """Render as human-readable text report."""
        lines = [
            f"Credit Risk Report  [{self.risk_rating.upper()}]",
            f"ID: {self.report_id}",
            f"Generated: {self.generated_at}",
            "",
            self.summary,
            "",
        ]
        for section in self.sections:
            lines.append(f"--- {section.title} ---")
            for key, val in section.metrics.items():
                lines.append(f"  {key}: {val:,.6f}")
            lines.append(f"  {section.narrative}")
            lines.append("")
        return "\n".join(lines)


# Risk rating thresholds (EL / EC ratio)
_CRITICAL_THRESHOLD = 0.50
_HIGH_THRESHOLD = 0.30
_MODERATE_THRESHOLD = 0.15


def _classify_risk(el: float, ec: float) -> str:
    """Classify risk based on expected loss / economic capital ratio."""
    if ec <= 0.0:
        return "low" if el <= 0.0 else "critical"
    ratio = el / ec
    if ratio > _CRITICAL_THRESHOLD:
        return "critical"
    if ratio > _HIGH_THRESHOLD:
        return "high"
    if ratio > _MODERATE_THRESHOLD:
        return "moderate"
    return "low"


class RiskReportBuilder:
    """Fluent builder for credit risk reports."""

    def __init__(self) -> None:
        self._sections: list[ReportSection] = []
        self._el: float = 0.0
        self._ec: float = 0.0
        self._stress_delta: float = 0.0

    def add_portfolio_section(
        self,
        expected_loss: float,
        unexpected_loss: float,
        economic_capital: float,
        hhi: float,
        gini: float,
        count: int,
        total_ead: float,
    ) -> RiskReportBuilder:
        """Add portfolio risk metrics section."""
        self._el = expected_loss
        self._ec = economic_capital

        concentration = "high" if hhi > 0.25 else "moderate" if hhi > 0.10 else "low"
        narrative = (
            f"Portfolio of {count} loans with total EAD {total_ead:,.2f}. "
            f"Concentration risk is {concentration} (HHI={hhi:.4f})."
        )
        self._sections.append(
            ReportSection(
                title="Portfolio Risk Metrics",
                metrics={
                    "expected_loss": expected_loss,
                    "unexpected_loss": unexpected_loss,
                    "economic_capital": economic_capital,
                    "hhi": hhi,
                    "gini": gini,
                },
                narrative=narrative,
            )
        )
        return self

    def add_ecl_section(
        self,
        total_ecl: float,
        horizon_quarters: int,
        horizon_method: str,
        pd_mean: float,
        lgd: float,
        confidence_low: float,
        confidence_high: float,
    ) -> RiskReportBuilder:
        """Add CECL expected credit loss section."""
        narrative = (
            f"Lifetime ECL of {total_ecl:,.6f} over {horizon_quarters}Q "
            f"horizon ({horizon_method}). Mean PD={pd_mean:.4f}, LGD={lgd:.2f}. "
            f"95% band: [{confidence_low:,.6f}, {confidence_high:,.6f}]."
        )
        self._sections.append(
            ReportSection(
                title="CECL Expected Credit Loss",
                metrics={
                    "total_ecl": total_ecl,
                    "horizon_quarters": float(horizon_quarters),
                    "pd_mean": pd_mean,
                    "lgd": lgd,
                    "confidence_low": confidence_low,
                    "confidence_high": confidence_high,
                },
                narrative=narrative,
            )
        )
        return self

    def add_stress_section(
        self,
        scenario_name: str,
        base_el: float,
        stressed_el: float,
        base_ec: float,
        stressed_ec: float,
    ) -> RiskReportBuilder:
        """Add stress testing results section."""
        delta_el = stressed_el - base_el
        delta_ec = stressed_ec - base_ec
        self._stress_delta = delta_el

        narrative = (
            f"Scenario '{scenario_name}': EL moves from {base_el:,.6f} to "
            f"{stressed_el:,.6f} ({delta_el:+,.6f}). "
            f"EC moves from {base_ec:,.6f} to {stressed_ec:,.6f} ({delta_ec:+,.6f})."
        )
        self._sections.append(
            ReportSection(
                title=f"Stress Test — {scenario_name}",
                metrics={
                    "base_el": base_el,
                    "stressed_el": stressed_el,
                    "delta_el": delta_el,
                    "base_ec": base_ec,
                    "stressed_ec": stressed_ec,
                    "delta_ec": delta_ec,
                },
                narrative=narrative,
            )
        )
        return self

    def add_fairness_section(
        self,
        protected_var: str,
        total_effect: float,
        direct_effect: float,
        indirect_paths: int,
        concerning_paths: int,
    ) -> RiskReportBuilder:
        """Add fair lending analysis section."""
        risk = "elevated" if concerning_paths > 0 else "acceptable"
        narrative = (
            f"Protected attribute '{protected_var}': total effect={total_effect:.6f}, "
            f"direct={direct_effect:.6f}. {indirect_paths} indirect paths, "
            f"{concerning_paths} concerning. Fair lending risk: {risk}."
        )
        self._sections.append(
            ReportSection(
                title="Fair Lending Analysis",
                metrics={
                    "total_effect": total_effect,
                    "direct_effect": direct_effect,
                    "indirect_paths": float(indirect_paths),
                    "concerning_paths": float(concerning_paths),
                },
                narrative=narrative,
            )
        )
        return self

    def build(self) -> RiskReport:
        """Build the final risk report with rating and summary."""
        rating = _classify_risk(self._el, self._ec)

        parts = [f"Risk rating: {rating.upper()}."]
        if self._el > 0:
            parts.append(f"Expected loss: {self._el:,.6f}.")
        if self._ec > 0:
            parts.append(f"Economic capital: {self._ec:,.6f}.")
        if self._stress_delta != 0:
            parts.append(f"Stress impact: {self._stress_delta:+,.6f} EL delta.")
        summary = " ".join(parts)

        return RiskReport(
            report_id=str(uuid.uuid4()),
            generated_at=datetime.now(UTC).isoformat(),
            sections=list(self._sections),
            summary=summary,
            risk_rating=rating,
        )
