"""Minimal Memory Governance Protocol adoption tests for abi-evals.

Verifies:
1. All required memory template files are present and have correct headings.
2. .abi/memory_policy.yml exists and has enforcement_mode: warn.
3. context_export produces deterministic output (identical hashes across two runs).
4. memory_drift_check JSON output has the expected schema shape.
"""
from __future__ import annotations

import json
import subprocess
import sys
from pathlib import Path

import pytest

REPO_ROOT = Path(__file__).resolve().parent.parent.parent
SCRIPT_LIB = REPO_ROOT / "script" / "_lib"

TEMPLATE_NAMES = [
    "STATE",
    "TASKS",
    "DECISIONS",
    "RISKS",
    "INTERFACES",
    "GLOSSARY",
    "RESUME_PROMPT",
]

TEMPLATE_HEADINGS: dict[str, list[str]] = {
    "STATE": ["## Current State", "## Phase", "## Known Issues"],
    "TASKS": ["## Active", "## Backlog", "## Completed"],
    "DECISIONS": ["## Decision Log", "## Pending"],
    "RISKS": ["## Risk Register", "## Mitigations"],
    "INTERFACES": ["## Interface Ledger", "## Contracts"],
    "GLOSSARY": ["## Terms"],
    "RESUME_PROMPT": ["## Context", "## Last Known State", "## Next Steps"],
}


class TestTemplatesPresent:
    def test_memory_dir_exists(self) -> None:
        assert (REPO_ROOT / "memory").is_dir()

    @pytest.mark.parametrize("name", TEMPLATE_NAMES)
    def test_template_file_exists(self, name: str) -> None:
        path = REPO_ROOT / "memory" / "templates" / f"{name}.md"
        assert path.exists(), f"Missing: memory/templates/{name}.md"

    @pytest.mark.parametrize("name", TEMPLATE_NAMES)
    def test_template_has_required_headings(self, name: str) -> None:
        path = REPO_ROOT / "memory" / "templates" / f"{name}.md"
        content = path.read_text(encoding="utf-8")
        for heading in TEMPLATE_HEADINGS[name]:
            assert heading in content, f"{name}.md missing heading: {heading}"


class TestMemoryPolicy:
    def test_policy_file_exists(self) -> None:
        assert (REPO_ROOT / ".abi" / "memory_policy.yml").exists()

    def test_policy_is_warn_mode(self) -> None:
        content = (REPO_ROOT / ".abi" / "memory_policy.yml").read_text(encoding="utf-8")
        assert "enforcement_mode: warn" in content

    def test_policy_schema_version(self) -> None:
        content = (REPO_ROOT / ".abi" / "memory_policy.yml").read_text(encoding="utf-8")
        assert "schema_version: 1" in content


class TestContextExportDeterminism:
    def test_context_export_produces_identical_output(self, tmp_path: Path) -> None:
        lib = SCRIPT_LIB / "context_export.py"
        run1 = tmp_path / "run1"
        run2 = tmp_path / "run2"
        r1 = subprocess.run(
            [sys.executable, str(lib), "--repo-root", str(REPO_ROOT), "--out", str(run1)],
            capture_output=True,
        )
        r2 = subprocess.run(
            [sys.executable, str(lib), "--repo-root", str(REPO_ROOT), "--out", str(run2)],
            capture_output=True,
        )
        assert r1.returncode == 0, f"run1 failed: {r1.stderr.decode()}"
        assert r2.returncode == 0, f"run2 failed: {r2.stderr.decode()}"
        p1 = json.loads((run1 / "pointers.json").read_text(encoding="utf-8"))
        p2 = json.loads((run2 / "pointers.json").read_text(encoding="utf-8"))
        assert p1["bundle_hash"] == p2["bundle_hash"], "pointers.json not deterministic"

    def test_pointers_json_schema(self, tmp_path: Path) -> None:
        lib = SCRIPT_LIB / "context_export.py"
        out = tmp_path / "bundle"
        result = subprocess.run(
            [sys.executable, str(lib), "--repo-root", str(REPO_ROOT), "--out", str(out)],
            capture_output=True,
        )
        assert result.returncode == 0, f"export failed: {result.stderr.decode()}"
        data = json.loads((out / "pointers.json").read_text(encoding="utf-8"))
        assert "bundle_hash" in data
        assert "file_count" in data
        assert "files" in data
        assert "schema" in data
        assert data["schema"] == "context-bundle/1.0"


class TestDriftCheckShape:
    def test_drift_check_exits_zero_warn_mode(self) -> None:
        lib = SCRIPT_LIB / "memory_drift_check.py"
        result = subprocess.run(
            [sys.executable, str(lib), "--repo-root", str(REPO_ROOT)],
            capture_output=True,
            cwd=str(REPO_ROOT),
        )
        assert result.returncode == 0

    def test_drift_check_json_output_shape(self) -> None:
        lib = SCRIPT_LIB / "memory_drift_check.py"
        result = subprocess.run(
            [sys.executable, str(lib), "--repo-root", str(REPO_ROOT), "--json"],
            capture_output=True,
            text=True,
            cwd=str(REPO_ROOT),
        )
        assert result.returncode == 0
        data = json.loads(result.stdout)
        assert "overall" in data
        assert data["overall"] in ("PASS", "WARN", "FAIL")
        assert "enforcement" in data
