"""Tests for CLI `credit compare` subcommand."""

from __future__ import annotations

import json
from pathlib import Path

import pytest

from orxaq.experiences.cli import main


def _capture_run(args: list[str]) -> tuple[str, int]:
    captured: list[str] = []
    import builtins
    orig = builtins.print

    def _cap(*a, **k):
        captured.append(" ".join(str(x) for x in a))
        orig(*a, **k)

    builtins.print = _cap
    try:
        rc = main(args)
    finally:
        builtins.print = orig
    return "\n".join(captured), rc


@pytest.fixture(scope="module")
def json_out() -> tuple[str, int]:
    return _capture_run(["credit", "compare", "--format", "json"])


@pytest.fixture(scope="module")
def text_out() -> tuple[str, int]:
    return _capture_run(["credit", "compare", "--format", "text"])


class TestCreditCompareJSON:
    def test_exits_zero(self, json_out): assert json_out[1] == 0

    def test_valid_json(self, json_out): assert isinstance(json.loads(json_out[0]), dict)

    def test_has_scenarios(self, json_out): assert "scenarios" in json.loads(json_out[0])

    def test_has_ecl_deltas(self, json_out): assert "ecl_deltas" in json.loads(json_out[0])

    def test_has_capital_waterfall(self, json_out):
        assert "capital_waterfall" in json.loads(json_out[0])

    def test_has_sensitivity_attribution(self, json_out):
        assert "sensitivity_attribution" in json.loads(json_out[0])

    def test_has_peak_loss_quarter(self, json_out):
        assert "peak_loss_quarter" in json.loads(json_out[0])

    def test_has_quarter_labels(self, json_out): assert "quarter_labels" in json.loads(json_out[0])

    def test_has_generated_at(self, json_out): assert "generated_at" in json.loads(json_out[0])

    def test_three_scenarios(self, json_out): assert len(json.loads(json_out[0])["scenarios"]) == 3

    def test_three_ecl_deltas(self, json_out):
        assert len(json.loads(json_out[0])["ecl_deltas"]) == 3

    def test_three_waterfall(self, json_out):
        assert len(json.loads(json_out[0])["capital_waterfall"]) == 3

    def test_attribution_sums_to_one(self, json_out):
        total = sum(json.loads(json_out[0])["sensitivity_attribution"].values())
        assert abs(total - 1.0) < 1e-3


class TestCreditCompareText:
    def test_exits_zero(self, text_out): assert text_out[1] == 0

    def test_non_empty(self, text_out): assert len(text_out[0].strip()) > 0

    def test_mentions_baseline(self, text_out): assert "baseline" in text_out[0].lower()


class TestCreditCompareVariants:
    def test_two_scenarios(self):
        _, rc = _capture_run(["credit", "compare", "--scenarios", "baseline,adverse"])
        assert rc == 0

    def test_two_scenarios_json(self):
        out, rc = _capture_run(
            ["credit", "compare", "--scenarios", "baseline,adverse", "--format", "json"]
        )
        assert rc == 0
        assert len(json.loads(out)["scenarios"]) == 2

    def test_custom_cet1(self):
        _, rc = _capture_run(["credit", "compare", "--starting-cet1", "0.15"])
        assert rc == 0

    def test_output_to_file(self, tmp_path: Path):
        out_file = tmp_path / "compare.json"
        _, rc = _capture_run(["credit", "compare", "--format", "json", "--output", str(out_file)])
        assert rc == 0 and out_file.exists()

    def test_output_file_valid_json(self, tmp_path: Path):
        out_file = tmp_path / "compare2.json"
        _capture_run(["credit", "compare", "--format", "json", "--output", str(out_file)])
        assert isinstance(json.loads(out_file.read_text()), dict)
