"""Behaviour-lock for the model-router classifier.

Pins `classify()`'s (tier, scores) output for every prompt in the
representative corpus. ANY change to the scoring rules, modifiers, or
decision logic that moves a tier or a score fails here — so a future
"optimization" that silently alters behaviour is caught.

This is the contract the perf work in this PR preserves: the hot-path
regex-precompile change MUST leave every one of these golden values
byte-identical.

Runs under pytest (CI) OR `python3 -m unittest` (offline, no deps).
"""

from __future__ import annotations

import sys
import unittest
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parent))

from _loader import load_model_router  # noqa: E402
from prompts import PROMPTS  # noqa: E402

# Golden snapshot captured from the classifier BEFORE the precompile change.
# (tier, {"cheap": int, "main": int, "hard": int}) — one per PROMPTS entry,
# same order. Regenerate ONLY with an intentional, reviewed behaviour change.
GOLDEN: list[tuple[str, dict[str, int]]] = [
    ("cheap", {"cheap": 5, "main": 0, "hard": 0}),
    ("cheap", {"cheap": 4, "main": 0, "hard": 0}),
    ("main", {"cheap": 0, "main": 5, "hard": 0}),
    ("hard", {"cheap": 0, "main": 0, "hard": 4}),
    ("main", {"cheap": 0, "main": 0, "hard": 0}),
    ("cheap", {"cheap": 22, "main": 0, "hard": 5}),
    ("cheap", {"cheap": 29, "main": 0, "hard": 0}),
    ("cheap", {"cheap": 18, "main": 0, "hard": 0}),
    ("cheap", {"cheap": 8, "main": 0, "hard": 0}),
    ("cheap", {"cheap": 8, "main": 0, "hard": 0}),
    ("main", {"cheap": 0, "main": 5, "hard": 0}),
    ("main", {"cheap": 0, "main": 0, "hard": 0}),
    ("main", {"cheap": 0, "main": 5, "hard": 0}),
    ("hard", {"cheap": 0, "main": 0, "hard": 43}),
    ("hard", {"cheap": 0, "main": 0, "hard": 39}),
    ("hard", {"cheap": 0, "main": 0, "hard": 31}),
    ("cheap", {"cheap": 13, "main": 0, "hard": 0}),
    ("main", {"cheap": 0, "main": 4, "hard": 0}),
    ("hard", {"cheap": 0, "main": 0, "hard": 6}),
    ("hard", {"cheap": 8, "main": 0, "hard": 37}),
]


class TestClassifyPins(unittest.TestCase):
    @classmethod
    def setUpClass(cls) -> None:
        cls.mr = load_model_router()

    def test_corpus_and_golden_aligned(self) -> None:
        self.assertEqual(
            len(GOLDEN), len(PROMPTS), "one GOLDEN entry per PROMPTS entry"
        )

    def test_classify_output_is_pinned(self) -> None:
        for prompt, (want_tier, want_scores) in zip(PROMPTS, GOLDEN):
            tier, scores, _triggered = self.mr.classify(prompt)
            self.assertEqual(tier, want_tier, f"tier drift: {prompt[:60]!r}")
            self.assertEqual(scores, want_scores, f"score drift: {prompt[:60]!r}")

    def test_classify_is_deterministic(self) -> None:
        for prompt in PROMPTS:
            first = self.mr.classify(prompt)
            second = self.mr.classify(prompt)
            self.assertEqual(first[0], second[0])
            self.assertEqual(first[1], second[1])


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