"""Tests for credit portfolio and stress CLI subcommands."""

from __future__ import annotations

import json
from io import StringIO
from unittest.mock import patch

from orxaq.experiences.cli import main


class TestCreditPortfolioCLI:
    """Test `orxaq credit portfolio` subcommand."""

    def test_portfolio_text_output(self) -> None:
        buf = StringIO()
        with patch("sys.stdout", buf):
            rc = main(["credit", "portfolio"])
        assert rc == 0
        output = buf.getvalue()
        assert "Portfolio Analytics" in output
        assert "Expected Loss" in output
        assert "HHI" in output

    def test_portfolio_json_output(self) -> None:
        buf = StringIO()
        with patch("sys.stdout", buf):
            rc = main(["--json", "credit", "portfolio"])
        assert rc == 0
        data = json.loads(buf.getvalue())
        assert "expected_loss" in data
        assert "unexpected_loss" in data
        assert "economic_capital" in data
        assert "hhi" in data
        assert "gini" in data
        assert "count" in data
        assert data["count"] > 0

    def test_portfolio_vintage_flag(self) -> None:
        buf = StringIO()
        with patch("sys.stdout", buf):
            rc = main(["credit", "portfolio", "--vintage"])
        assert rc == 0
        output = buf.getvalue()
        assert "Vintage Analysis" in output

    def test_portfolio_vintage_json(self) -> None:
        buf = StringIO()
        with patch("sys.stdout", buf):
            rc = main(["--json", "credit", "portfolio", "--vintage"])
        assert rc == 0
        data = json.loads(buf.getvalue())
        assert "vintages" in data

    def test_portfolio_metrics_positive(self) -> None:
        buf = StringIO()
        with patch("sys.stdout", buf):
            rc = main(["--json", "credit", "portfolio"])
        assert rc == 0
        data = json.loads(buf.getvalue())
        assert data["expected_loss"] >= 0
        assert data["total_ead"] > 0
        assert 0 <= data["hhi"] <= 1


class TestCreditStressCLI:
    """Test `orxaq credit stress` subcommand."""

    def test_stress_adverse_text(self) -> None:
        buf = StringIO()
        with patch("sys.stdout", buf):
            rc = main(["credit", "stress", "--scenario", "adverse"])
        assert rc == 0
        output = buf.getvalue()
        assert "Stress Test: adverse" in output
        assert "Expected Loss" in output

    def test_stress_adverse_json(self) -> None:
        buf = StringIO()
        with patch("sys.stdout", buf):
            rc = main(["--json", "credit", "stress", "--scenario", "adverse"])
        assert rc == 0
        data = json.loads(buf.getvalue())
        assert data["scenario"] == "adverse"
        assert "base" in data
        assert "stressed" in data
        assert "delta_el" in data

    def test_stress_baseline(self) -> None:
        buf = StringIO()
        with patch("sys.stdout", buf):
            rc = main(["--json", "credit", "stress", "--scenario", "baseline"])
        assert rc == 0
        data = json.loads(buf.getvalue())
        assert data["scenario"] == "baseline"

    def test_stress_severely_adverse(self) -> None:
        buf = StringIO()
        with patch("sys.stdout", buf):
            rc = main(["--json", "credit", "stress", "--scenario", "severely_adverse"])
        assert rc == 0
        data = json.loads(buf.getvalue())
        assert data["scenario"] == "severely_adverse"

    def test_stress_unknown_scenario(self) -> None:
        buf = StringIO()
        with patch("sys.stdout", buf):
            rc = main(["credit", "stress", "--scenario", "unknown_scenario"])
        assert rc == 1

    def test_stress_default_scenario(self) -> None:
        buf = StringIO()
        with patch("sys.stdout", buf):
            rc = main(["--json", "credit", "stress"])
        assert rc == 0
        data = json.loads(buf.getvalue())
        assert data["scenario"] == "adverse"  # default

    def test_stress_has_positive_delta(self) -> None:
        """Adverse scenario should increase expected loss."""
        buf = StringIO()
        with patch("sys.stdout", buf):
            rc = main(["--json", "credit", "stress", "--scenario", "severely_adverse"])
        assert rc == 0
        data = json.loads(buf.getvalue())
        # Stressed EL should differ from base (may be higher or lower
        # depending on synthetic data, so just check it's computed)
        assert isinstance(data["delta_el"], float)
