"""Executable conditional-rollback teaching fixture. No external services.
Run: python3 conditional-rollback.py
Not a production MCP server, auth system, or persistent receipt store.
"""
from dataclasses import dataclass
from threading import Lock
import unittest


@dataclass(frozen=True)
class Recovery:
    operation: str
    resource: str
    before: str
    written_revision: int


class ResourceService:
    def __init__(self):
        self.value = "original"
        self.revision = 0
        self.lock = Lock()
        self.operations = {}
        self.receipts = {}

    def write(self, value):
        with self.lock:
            self.value = value
            self.revision += 1

    def forward(self, operation):
        with self.lock:
            if operation in self.operations:
                raise ValueError("operation already exists")
            before = self.value
            self.value = "agent-change"
            self.revision += 1
            record = Recovery(operation, "staging/routing", before, self.revision)
            self.operations[operation] = record
            return record

    def recover(self, record, *, authorised):
        with self.lock:
            # Caller supplies the auth verdict only in this teaching fixture.
            # A real service must verify identity, scope and expiry itself.
            if not authorised:
                return "denied"
            if self.operations.get(record.operation) != record:
                return "invalid_record"
            if record.operation in self.receipts:
                return self.receipts[record.operation]
            if self.revision != record.written_revision:
                self.receipts[record.operation] = "conflict"
                return "conflict"
            self.value = record.before
            self.revision += 1
            self.receipts[record.operation] = "restored"
            return "restored"


class RecoveryTests(unittest.TestCase):
    def setUp(self):
        self.service = ResourceService()
        self.record = self.service.forward("op-1")

    def test_unchanged_resource_restores(self):
        self.assertEqual(self.service.recover(self.record, authorised=True), "restored")
        self.assertEqual(self.service.value, "original")

    def test_human_fix_survives(self):
        self.service.write("human-fix")
        self.assertEqual(self.service.recover(self.record, authorised=True), "conflict")
        self.assertEqual(self.service.value, "human-fix")

    def test_change_away_and_back_is_still_a_conflict(self):
        self.service.write("human-fix")
        self.service.write("agent-change")
        self.assertEqual(self.service.recover(self.record, authorised=True), "conflict")

    def test_expired_authority_does_not_write(self):
        self.assertEqual(self.service.recover(self.record, authorised=False), "denied")
        self.assertEqual(self.service.value, "agent-change")

    def test_duplicate_recovery_returns_receipt_without_writing(self):
        self.service.recover(self.record, authorised=True)
        self.service.write("later-fix")
        revision = self.service.revision
        self.assertEqual(self.service.recover(self.record, authorised=True), "restored")
        self.assertEqual(self.service.value, "later-fix")
        self.assertEqual(self.service.revision, revision)

    def test_caller_cannot_replace_before_state(self):
        fake = Recovery("op-1", "staging/routing", "unsafe", self.record.written_revision)
        self.assertEqual(self.service.recover(fake, authorised=True), "invalid_record")
        self.assertEqual(self.service.value, "agent-change")


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