"""Tests for break-glass / emergency access."""

import pytest

from pyauthz import (
    BreakGlassManager,
    Resource,
    Subject,
)


class TestBreakGlassManager:
    def test_authorized_subject_gets_access(self):
        bg = BreakGlassManager(allowed_subjects={"oncall-admin"})
        user = Subject(id="oncall-admin", roles=[])
        record = Resource(id="patient-1", type="medical")

        decision = bg.authorize(user, "pii:read", record, justification="Patient emergency")
        assert decision.allowed
        assert "__break_glass__" in decision.matched_policies
        assert "BREAK-GLASS" in decision.reasoning[0]

    def test_unauthorized_subject_raises(self):
        bg = BreakGlassManager(allowed_subjects={"oncall-admin"})
        user = Subject(id="random-user", roles=[])
        record = Resource(id="patient-1", type="medical")

        with pytest.raises(PermissionError, match="not authorized"):
            bg.authorize(user, "pii:read", record, justification="I want access")

    def test_empty_justification_raises(self):
        bg = BreakGlassManager(allowed_subjects={"oncall-admin"})
        user = Subject(id="oncall-admin", roles=[])
        record = Resource(id="patient-1", type="medical")

        with pytest.raises(ValueError, match="non-empty justification"):
            bg.authorize(user, "pii:read", record, justification="")

    def test_whitespace_justification_raises(self):
        bg = BreakGlassManager(allowed_subjects={"oncall-admin"})
        user = Subject(id="oncall-admin", roles=[])
        record = Resource(id="patient-1", type="medical")

        with pytest.raises(ValueError, match="non-empty justification"):
            bg.authorize(user, "pii:read", record, justification="   ")

    def test_events_recorded(self):
        bg = BreakGlassManager(allowed_subjects={"oncall-admin"})
        user = Subject(id="oncall-admin", roles=[])
        record = Resource(id="patient-1", type="medical")

        bg.authorize(user, "pii:read", record, justification="Emergency")
        events = bg.get_events()
        assert len(events) == 1
        assert events[0].subject_id == "oncall-admin"
        assert events[0].justification == "Emergency"
        assert events[0].resource_type == "medical"

    def test_is_authorized(self):
        bg = BreakGlassManager(allowed_subjects={"admin"})
        assert bg.is_authorized(Subject(id="admin", roles=[]))
        assert not bg.is_authorized(Subject(id="user", roles=[]))

    def test_add_remove_subject(self):
        bg = BreakGlassManager()
        assert not bg.is_authorized(Subject(id="new-admin", roles=[]))
        bg.add_subject("new-admin")
        assert bg.is_authorized(Subject(id="new-admin", roles=[]))
        bg.remove_subject("new-admin")
        assert not bg.is_authorized(Subject(id="new-admin", roles=[]))

    def test_metadata_in_event(self):
        bg = BreakGlassManager(allowed_subjects={"oncall-admin"})
        user = Subject(id="oncall-admin", roles=[])
        record = Resource(id="patient-1", type="medical")

        bg.authorize(
            user,
            "pii:read",
            record,
            justification="Emergency",
            incident_id="INC-123",
        )
        events = bg.get_events()
        assert events[0].metadata["incident_id"] == "INC-123"

    def test_justification_in_decision_reasoning(self):
        bg = BreakGlassManager(allowed_subjects={"admin"})
        user = Subject(id="admin", roles=[])
        record = Resource(id="r-1", type="records")

        decision = bg.authorize(user, "read", record, justification="Production incident")
        assert any("Production incident" in r for r in decision.reasoning)
