"""Tests for orxaq demo regulatory command."""

from __future__ import annotations

import json
import sys
from io import StringIO
from pathlib import Path

import pytest

from orxaq.credit.filing import FILING_OUTPUT_FILES
from orxaq.experiences.demo import run_regulatory_demo

# ── Shared fixture — run the demo once per module ─────────────


@pytest.fixture(scope="module")
def demo_result(tmp_path_factory):
    out = tmp_path_factory.mktemp("demo_regulatory")
    return run_regulatory_demo(
        output_dir=str(out),
        institution_id="TEST_BANK_001",
        period="2025Q4",
        seed=42,
    )


@pytest.fixture(scope="module")
def demo_outdir(demo_result):
    return Path(demo_result["output_dir"])


# ── Return value structure ─────────────────────────────────────


class TestDemoReturnDict:
    def test_required_keys_present(self, demo_result):
        for key in (
            "output_dir",
            "files",
            "institution_id",
            "period",
            "duration_seconds",
            "compliance_status",
            "audit_entries",
        ):
            assert key in demo_result, f"Missing key: {key}"

    def test_institution_id_preserved(self, demo_result):
        assert demo_result["institution_id"] == "TEST_BANK_001"

    def test_period_preserved(self, demo_result):
        assert demo_result["period"] == "2025Q4"

    def test_compliance_status_pass(self, demo_result):
        assert demo_result["compliance_status"] == "PASS"

    def test_duration_positive(self, demo_result):
        assert demo_result["duration_seconds"] > 0

    def test_audit_entries_positive(self, demo_result):
        assert demo_result["audit_entries"] > 0

    def test_files_list_length(self, demo_result):
        assert len(demo_result["files"]) == len(FILING_OUTPUT_FILES)


# ── Output files on disk ───────────────────────────────────────


class TestDemoOutputFiles:
    def test_all_output_files_exist(self, demo_outdir):
        for fname in FILING_OUTPUT_FILES:
            assert (demo_outdir / fname).exists(), f"Missing: {fname}"

    def test_manifest_contains_checksums(self, demo_outdir):
        manifest = json.loads((demo_outdir / "manifest.json").read_text())
        files_entry = manifest.get("files") or manifest
        # manifest must contain sha256 checksums
        found = False
        if isinstance(files_entry, list):
            found = any("sha256" in str(e) for e in files_entry)
        elif isinstance(files_entry, dict):
            found = any("sha256" in str(v) for v in files_entry.values())
        assert found, "manifest.json has no sha256 entries"


# ── CLI integration ────────────────────────────────────────────


class TestDemoCLI:
    def test_cli_text_mode_exits_zero(self, tmp_path):
        from orxaq.experiences.cli import main

        rc = main(
            [
                "demo",
                "regulatory",
                "--output-dir",
                str(tmp_path / "cli_text"),
                "--seed",
                "1",
            ]
        )
        assert rc == 0

    def test_cli_json_mode_exits_zero(self, tmp_path):
        from orxaq.experiences.cli import main

        captured = StringIO()
        sys.stdout = captured
        try:
            rc = main(
                [
                    "--json",
                    "demo",
                    "regulatory",
                    "--output-dir",
                    str(tmp_path / "cli_json"),
                    "--seed",
                    "1",
                ]
            )
        finally:
            sys.stdout = sys.__stdout__
        assert rc == 0

    def test_cli_json_mode_output_dir_key(self, tmp_path):
        from orxaq.experiences.cli import main

        out = tmp_path / "cli_json_key"
        captured = StringIO()
        sys.stdout = captured
        try:
            main(
                [
                    "--json",
                    "demo",
                    "regulatory",
                    "--output-dir",
                    str(out),
                    "--seed",
                    "2",
                ]
            )
        finally:
            sys.stdout = sys.__stdout__
        data = json.loads(captured.getvalue())
        assert "output_dir" in data

    def test_cli_json_mode_files_length(self, tmp_path):
        from orxaq.experiences.cli import main

        out = tmp_path / "cli_json_files"
        captured = StringIO()
        sys.stdout = captured
        try:
            main(
                [
                    "--json",
                    "demo",
                    "regulatory",
                    "--output-dir",
                    str(out),
                    "--seed",
                    "3",
                ]
            )
        finally:
            sys.stdout = sys.__stdout__
        data = json.loads(captured.getvalue())
        assert len(data["files"]) == len(FILING_OUTPUT_FILES)


# ── Determinism & isolation ────────────────────────────────────


class TestDemoProperties:
    def test_different_institution_ids_produce_different_manifest(self, tmp_path):
        r1 = run_regulatory_demo(
            output_dir=str(tmp_path / "b1"),
            institution_id="BANK_A",
            period="2025Q4",
            seed=42,
        )
        r2 = run_regulatory_demo(
            output_dir=str(tmp_path / "b2"),
            institution_id="BANK_B",
            period="2025Q4",
            seed=42,
        )
        m1 = json.loads((Path(r1["output_dir"]) / "cecl_disclosure.json").read_text())
        m2 = json.loads((Path(r2["output_dir"]) / "cecl_disclosure.json").read_text())
        # institution ids must differ in CECL disclosure
        id1 = m1.get("institution_id") or m1.get("institution") or str(m1)
        id2 = m2.get("institution_id") or m2.get("institution") or str(m2)
        assert id1 != id2 or r1["institution_id"] != r2["institution_id"]

    def test_demo_deterministic_same_seed(self, tmp_path):
        r1 = run_regulatory_demo(
            output_dir=str(tmp_path / "det1"),
            institution_id="DET_BANK",
            period="2025Q4",
            seed=99,
        )
        r2 = run_regulatory_demo(
            output_dir=str(tmp_path / "det2"),
            institution_id="DET_BANK",
            period="2025Q4",
            seed=99,
        )
        # Both runs must produce same set of files and same institution/period
        m1 = json.loads((Path(r1["output_dir"]) / "manifest.json").read_text())
        m2 = json.loads((Path(r2["output_dir"]) / "manifest.json").read_text())
        assert set(m1.get("files", {}).keys()) == set(m2.get("files", {}).keys())
        assert m1.get("institution_id") == m2.get("institution_id")
        assert m1.get("period") == m2.get("period")
        # scenario_comparison.csv and schedule_h1.csv are timestamp-free → stable
        stable_files = {"scenario_comparison.csv", "schedule_h1.csv"}
        files1 = m1.get("files", {})
        files2 = m2.get("files", {})
        for fname in stable_files:
            if fname in files1 and fname in files2:
                assert files1[fname].get("sha256") == files2[fname].get("sha256")
