"""Tests for evidence pack builder — full roundtrip build + validate."""

from __future__ import annotations

import json
from pathlib import Path

import pytest

from abi_control_core.sdk.evidence_pack import EvidencePackBuilder
from abi_control_core.sdk.validate import validate_json


@pytest.fixture
def run_manifest() -> dict:
    return {
        "schema_version": "run-manifest/1.0",
        "run_id": "aabb0011",
        "gate": "intent-gate",
        "mode": "exploration",
        "trigger": "manual",
        "started_at": "2026-02-25T10:00:00Z",
        "completed_at": "2026-02-25T10:05:00Z",
        "intent_gate_hash": "sha256:" + "a" * 64,
        "verdict": "pass",
        "summary": {"total": 3, "passed": 3, "failed": 0, "skipped": 0, "blocker": 0},
    }


@pytest.fixture
def plan_graph() -> dict:
    return {
        "schema_version": "plan-graph/1.0",
        "run_id": "aabb0011",
        "nodes": [
            {"node_id": "n1", "name": "validate", "status": "completed"},
            {"node_id": "n2", "name": "build", "depends_on": ["n1"], "status": "completed"},
        ],
    }


class TestEvidencePackRoundtrip:
    """Build a full evidence pack and verify all outputs."""

    def test_minimal_pack(self, tmp_evidence_dir: Path, run_manifest: dict) -> None:
        """A pack with just a manifest should be valid."""
        builder = EvidencePackBuilder(tmp_evidence_dir, "aabb0011")
        builder.set_manifest(run_manifest)
        summary = builder.finalize()

        assert summary["run_id"] == "aabb0011"
        assert "manifest.json" in summary["components"].values()

        # Verify the manifest file exists and is valid JSON
        manifest_path = Path(summary["pack_dir"]) / "manifest.json"
        assert manifest_path.exists()
        data = json.loads(manifest_path.read_text(encoding="utf-8"))
        validate_json(data, "run_manifest.schema.json")

    def test_full_pack(self, tmp_evidence_dir: Path, run_manifest: dict, plan_graph: dict) -> None:
        """A full evidence pack with all components."""
        builder = EvidencePackBuilder(tmp_evidence_dir, "aabb0011")
        builder.set_manifest(run_manifest)
        builder.set_plan_graph(plan_graph)
        builder.add_events([
            {
                "schema_version": "event-envelope/1.0",
                "event_id": "e1",
                "event_type": "gate_start",
                "ts": "2026-02-25T10:00:00Z",
                "run_id": "aabb0011",
            }
        ])
        builder.add_spans([
            {
                "span_id": "ccdd0022",
                "name": "schema_validate",
                "start_time": "2026-02-25T10:00:00Z",
                "end_time": "2026-02-25T10:00:01Z",
                "status": "ok",
            }
        ])
        builder.add_policy_decisions([
            {
                "schema_version": "policy-decision/1.0",
                "run_id": "aabb0011",
                "policy_id": "INTENT-001",
                "decision": "allow",
                "decided_at": "2026-02-25T10:00:00Z",
            }
        ])
        builder.set_budget_receipts({
            "schema_version": "budget-receipt/1.0",
            "run_id": "aabb0011",
            "gate": "intent-gate",
            "generated_at": "2026-02-25T10:05:00Z",
            "budget_policy": {"enforcement_mode": "warn", "total_planned": 1000, "total_max": 2000},
            "steps": [],
            "summary": {
                "total_planned": 1000,
                "total_reserved": 1000,
                "total_actual": 500,
                "total_released": 500,
                "breaches": 0,
                "verdict": "within_budget",
            },
        })
        builder.set_eval_results({
            "schema_version": "eval-result/1.0",
            "suite_id": "test-suite-1",
            "run_id": "aabb0011",
            "evaluated_at": "2026-02-25T10:05:00Z",
            "results": [{"case_id": "tc-1", "status": "pass"}],
            "summary": {"total": 1, "passed": 1, "failed": 0},
        })

        # Add a CAS artifact
        digest = builder.add_artifact(b"Hello, evidence!")
        assert len(digest) == 64

        summary = builder.finalize()

        # Check all components are registered
        assert "run_manifest" in summary["components"]
        assert "plan_graph" in summary["components"]
        assert "events" in summary["components"]
        assert "spans" in summary["components"]
        assert "policy_decisions" in summary["components"]
        assert "budget_receipts" in summary["components"]
        assert "eval_results" in summary["components"]

        # Check hashes file exists
        hashes_path = Path(summary["pack_dir"]) / "hashes.json"
        assert hashes_path.exists()
        hashes = json.loads(hashes_path.read_text(encoding="utf-8"))
        assert len(hashes) > 0
        assert all(v.startswith("sha256:") for v in hashes.values())

        # Check evidence pack manifest exists and is valid
        ep_manifest_path = Path(summary["pack_dir"]) / "evidence_pack_manifest.json"
        assert ep_manifest_path.exists()
        ep_manifest = json.loads(ep_manifest_path.read_text(encoding="utf-8"))
        validate_json(ep_manifest, "evidence_pack_manifest.schema.json")

        # Check artifacts dir
        artifacts_dir = Path(summary["pack_dir"]) / "artifacts"
        assert artifacts_dir.exists()
        assert len(list(artifacts_dir.iterdir())) == 1

    def test_artifact_roundtrip(self, tmp_evidence_dir: Path, run_manifest: dict) -> None:
        """Artifact stored in CAS must be retrievable."""
        builder = EvidencePackBuilder(tmp_evidence_dir, "aabb0011")
        builder.set_manifest(run_manifest)
        data = b"deterministic content"
        digest = builder.add_artifact(data)
        builder.finalize()

        artifact_path = tmp_evidence_dir / "aabb0011" / "artifacts" / digest
        assert artifact_path.exists()
        assert artifact_path.read_bytes() == data

    def test_hashes_are_deterministic(self, tmp_evidence_dir: Path, run_manifest: dict) -> None:
        """Building the same pack twice must produce identical hashes."""
        for i in range(2):
            d = tmp_evidence_dir / f"run{i}"
            d.mkdir()
            builder = EvidencePackBuilder(d, "aabb0011")
            builder.set_manifest(run_manifest)
            builder.finalize()

        path_0 = tmp_evidence_dir / "run0" / "aabb0011" / "hashes.json"
        path_1 = tmp_evidence_dir / "run1" / "aabb0011" / "hashes.json"
        hashes_0 = json.loads(path_0.read_text(encoding="utf-8"))
        hashes_1 = json.loads(path_1.read_text(encoding="utf-8"))
        assert hashes_0 == hashes_1
