#!/usr/bin/env python3
"""Focused behavioral tests for the canonical-version gate."""

from __future__ import annotations

from pathlib import Path
import shutil
import subprocess
import sys
import re
import tempfile
import unittest

ROOT = Path(__file__).resolve().parents[1]
CHECKER = ROOT / "ci" / "release" / "check-version-consistency.py"
CANONICAL_VERSION = re.search(r'(?m)^version = "([^"]+)"$', (ROOT / "adapter" / "omp-spt.toml").read_text(encoding="utf-8")).group(1)
FILES = (
    Path("adapter/omp-spt.toml"),
    Path("adapter/strings/package.json"),
    Path("tools/omp-spt/Cargo.toml"),
    Path("tools/omp-spt/Cargo.lock"),
    Path("CHANGELOG.md"),
    Path("README.md"),
    Path("docs-site/src/quickstart.md"),
    Path("docs/PARITY.md"),
)


def fixture() -> tempfile.TemporaryDirectory[str]:
    work = tempfile.TemporaryDirectory()
    root = Path(work.name)
    for relative in FILES:
        destination = root / relative
        destination.parent.mkdir(parents=True, exist_ok=True)
        shutil.copyfile(ROOT / relative, destination)
    return work


def run_checker(root: Path) -> subprocess.CompletedProcess[str]:
    return subprocess.run(
        [sys.executable, str(CHECKER), "--root", str(root)],
        text=True,
        capture_output=True,
        check=False,
    )


def replace(path: Path, old: str, new: str) -> None:
    text = path.read_text(encoding="utf-8")
    if old not in text:
        raise AssertionError(f"fixture token missing from {path}: {old!r}")
    path.write_text(text.replace(old, new, 1), encoding="utf-8", newline="\n")


# [unit->REQ-DIST-VERSION-CONSISTENCY]
# [unit->REQ-PARITY-BASELINE]
class VersionConsistencyTests(unittest.TestCase):
    def test_current_artifacts_match_canonical_manifest(self) -> None:
        result = run_checker(ROOT)
        self.assertEqual(result.returncode, 0, result.stdout + result.stderr)
        self.assertIn(f"VERSION-CONSISTENCY OK: {CANONICAL_VERSION}", result.stdout)

    def test_each_versioned_artifact_mismatch_is_rejected(self) -> None:
        mutations = (
            (Path("tools/omp-spt/Cargo.toml"), f'version = "{CANONICAL_VERSION}"', 'version = "9.9.9"'),
            (
                Path("tools/omp-spt/Cargo.lock"),
                f'name = "omp-spt"\nversion = "{CANONICAL_VERSION}"',
                'name = "omp-spt"\nversion = "9.9.9"',
            ),
            (
                Path("adapter/strings/package.json"),
                f'"version": "{CANONICAL_VERSION}"',
                '"version": "9.9.9"',
            ),
            (Path("CHANGELOG.md"), f"## [{CANONICAL_VERSION}]", "## [9.9.9]"),
            (Path("README.md"), f"The v{CANONICAL_VERSION} release asset", "The v9.9.9 release asset"),
            (
                Path("docs-site/src/quickstart.md"),
                f"The v{CANONICAL_VERSION} `omp-spt` release",
                "The v9.9.9 `omp-spt` release",
            ),
        )
        for relative, old, new in mutations:
            with self.subTest(path=str(relative)), fixture() as work:
                root = Path(work)
                replace(root / relative, old, new)
                result = run_checker(root)
                self.assertEqual(result.returncode, 1, result.stdout + result.stderr)
                self.assertIn("does not match canonical manifest version", result.stdout)


    def test_stale_or_unversioned_parity_baseline_is_rejected(self) -> None:
        # The sister token moves with every parity-informed release; read the live one
        # rather than pinning a version this test would then have to chase.
        baseline = re.search(
            r"^Current baseline: `omp-spt v[0-9.]+` → (`BigscreenVR/claude-spt-bs v[0-9.]+`\.)$",
            (ROOT / "docs" / "PARITY.md").read_text(encoding="utf-8"),
            re.MULTILINE,
        )
        self.assertIsNotNone(baseline, "PARITY.md carries no versioned sister baseline")
        mutations = (
            (
                f"Current baseline: `omp-spt v{CANONICAL_VERSION}`",
                "Current baseline: `omp-spt v9.9.9`",
                "does not match canonical manifest version",
            ),
            (
                baseline.group(1),
                "`BigscreenVR/claude-spt-bs main`.",
                "cannot find versioned claude-spt parity baseline",
            ),
        )
        for old, new, expected in mutations:
            with self.subTest(replacement=new), fixture() as work:
                root = Path(work)
                replace(root / "docs" / "PARITY.md", old, new)
                result = run_checker(root)
                self.assertEqual(result.returncode, 1, result.stdout + result.stderr)
                self.assertIn(expected, result.stdout)

if __name__ == "__main__":
    unittest.main(verbosity=2)
