"""Tests for the reporting module."""

from __future__ import annotations

import json

from obliteratus.reporting.report import (
    REPORT_SCHEMA_VERSION,
    AblationReport,
    AblationResult,
)


def _make_report() -> AblationReport:
    report = AblationReport(model_name="test-model")
    report.add_baseline({"perplexity": 25.0, "accuracy": 0.85})
    report.add_result(
        AblationResult(
            strategy="layer_removal",
            component="layer_0",
            description="Remove layer 0",
            metrics={"perplexity": 30.0, "accuracy": 0.80},
        )
    )
    report.add_result(
        AblationResult(
            strategy="layer_removal",
            component="layer_1",
            description="Remove layer 1",
            metrics={"perplexity": 50.0, "accuracy": 0.60},
        )
    )
    return report


class TestAblationReport:
    def test_to_dataframe(self):
        report = _make_report()
        df = report.to_dataframe()
        assert len(df) == 2
        assert "perplexity" in df.columns
        assert "perplexity_delta" in df.columns
        assert "perplexity_pct_change" in df.columns

    def test_save_json(self, tmp_path):
        report = _make_report()
        out = tmp_path / "results.json"
        report.save_json(out)
        data = json.loads(out.read_text())
        assert data["model_name"] == "test-model"
        assert len(data["results"]) == 2
        assert data["baseline_metrics"]["perplexity"] == 25.0
        assert data["schema_version"] == REPORT_SCHEMA_VERSION

    def test_save_csv(self, tmp_path):
        report = _make_report()
        out = tmp_path / "results.csv"
        report.save_csv(out)
        text = out.read_text()
        assert "layer_0" in text
        assert "perplexity" in text

    def test_delta_calculation(self):
        report = _make_report()
        df = report.to_dataframe()
        row0 = df[df["component"] == "layer_0"].iloc[0]
        assert row0["perplexity_delta"] == 5.0  # 30 - 25
        assert abs(row0["perplexity_pct_change"] - 20.0) < 0.01

    def test_plot_impact(self, tmp_path):
        report = _make_report()
        out = tmp_path / "impact.png"
        report.plot_impact(metric="perplexity", output_path=out)
        assert out.exists()
        assert out.stat().st_size > 0

    def test_measured_zero_and_unavailable_are_distinct(self):
        report = AblationReport(model_name="test")
        report.add_baseline({"refusal_rate": 0.0, "perplexity": None})
        report.add_result(AblationResult(
            strategy="advanced",
            component="all",
            description="partial evaluation",
            metrics={"refusal_rate": 0.0, "perplexity": None},
        ))
        data = report.to_dict()
        assert data["baseline_metric_status"] == {
            "perplexity": "unavailable", "refusal_rate": "measured",
        }
        assert data["results"][0]["metric_status"] == {
            "perplexity": "unavailable", "refusal_rate": "measured",
        }
        assert data["results"][0]["metrics"]["refusal_rate"] == 0.0

    def test_json_is_deterministic_finite_and_redacted(self, tmp_path):
        report = AblationReport(model_name="/private/models/secret-model")
        report.add_baseline({"score": float("nan")})
        report.add_result(AblationResult(
            strategy="/private/run/advanced",
            component="layer_0",
            description="artifact /private/run/output hf_abcdefghijkl",
            metrics={"score": float("inf")},
            metadata={
                "token": "hf_abcdefghijkl",
                "artifact": "/private/run/checkpoint.bin",
            },
        ))
        first = tmp_path / "first.json"
        second = tmp_path / "second.json"
        report.save_json(first)
        report.save_json(second)
        assert first.read_bytes() == second.read_bytes()
        text = first.read_text()
        assert "/private/" not in text
        assert "hf_abcdefghijkl" not in text
        assert '"token"' not in text
        assert "NaN" not in text and "Infinity" not in text

    def test_public_model_identifier_is_preserved(self):
        report = AblationReport(model_name="org/model-name")
        assert report.to_dict()["model_name"] == "org/model-name"
