import unittest
from audit_demo import Call, DemoLegacySystem, StatusService


class AuditTests(unittest.TestCase):
    def setUp(self):
        self.legacy, self.audit = DemoLegacySystem(), []
        self.service = StatusService(self.legacy, {"allowed": {"DEMO-42"}}, self.audit, str)

    def test_denied_before_read(self):
        with self.assertRaises(PermissionError):
            self.service.query(Call("denied", "i1"), "DEMO-42")
        self.assertEqual(self.legacy.events, [])
        self.assertEqual([x["outcome"] for x in self.audit], ["denied"])

    def test_reference_scope(self):
        with self.assertRaises(PermissionError):
            self.service.query(Call("allowed", "i2"), "OTHER")
        self.assertEqual(self.legacy.events, [])

    def test_success_uses_actual_legacy_event(self):
        self.assertEqual(self.service.query(Call("allowed", "i3"), "DEMO-42"), {"status": "ready"})
        self.assertEqual(self.audit[1]["legacy_event_id"], self.legacy.events[0]["event_id"])
        self.assertNotIn("reference", self.audit[1])

    def test_later_failure_does_not_erase_read(self):
        def fail(status):
            raise TimeoutError()
        self.service.render = fail
        with self.assertRaises(TimeoutError):
            self.service.query(Call("allowed", "i4"), "DEMO-42")
        self.assertEqual([(x["stage"], x["outcome"]) for x in self.audit],
                         [("read", "started"), ("read", "completed"), ("render", "failed")])
        self.assertEqual(len(self.legacy.events), 1)

    def test_read_timeout_is_unknown_not_unread(self):
        def fail(reference):
            raise TimeoutError()
        self.legacy.read_status = fail
        with self.assertRaises(TimeoutError):
            self.service.query(Call("allowed", "i5"), "DEMO-42")
        self.assertEqual(self.audit[-1]["outcome"], "unknown")
        self.assertNotIn("legacy_event_id", self.audit[-1])

    def test_read_occurred_but_response_was_lost(self):
        original_read = self.legacy.read_status
        def lost_response(reference):
            original_read(reference)
            raise TimeoutError()
        self.legacy.read_status = lost_response
        with self.assertRaises(TimeoutError):
            self.service.query(Call("allowed", "i6"), "DEMO-42")
        self.assertEqual(len(self.legacy.events), 1)
        self.assertEqual(self.audit[-1]["outcome"], "unknown")
        self.assertNotIn("legacy_event_id", self.audit[-1])


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