"""Tests for temporal permissions."""

from datetime import UTC, datetime, timedelta

from pyauthz import TemporalRole, TemporalRoleStore


class TestTemporalRole:
    def test_active_with_no_bounds(self):
        tr = TemporalRole(role_name="admin", subject_id="alice")
        assert tr.is_active()

    def test_active_within_window(self):
        now = datetime.now(UTC)
        tr = TemporalRole(
            role_name="admin",
            subject_id="alice",
            effective_from=now - timedelta(hours=1),
            expires_at=now + timedelta(hours=1),
        )
        assert tr.is_active(now)

    def test_not_yet_effective(self):
        now = datetime.now(UTC)
        tr = TemporalRole(
            role_name="admin",
            subject_id="alice",
            effective_from=now + timedelta(hours=1),
        )
        assert not tr.is_active(now)

    def test_expired(self):
        now = datetime.now(UTC)
        tr = TemporalRole(
            role_name="admin",
            subject_id="alice",
            expires_at=now - timedelta(hours=1),
        )
        assert not tr.is_active(now)

    def test_metadata(self):
        tr = TemporalRole(
            role_name="admin",
            subject_id="alice",
            metadata={"granted_by": "system"},
        )
        assert tr.metadata["granted_by"] == "system"


class TestTemporalRoleStore:
    def test_assign_and_get_active(self):
        store = TemporalRoleStore()
        store.assign(TemporalRole(role_name="admin", subject_id="alice"))
        store.assign(TemporalRole(role_name="editor", subject_id="alice"))
        assert sorted(store.get_active_roles("alice")) == ["admin", "editor"]

    def test_get_active_excludes_expired(self):
        now = datetime.now(UTC)
        store = TemporalRoleStore()
        store.assign(
            TemporalRole(
                role_name="admin",
                subject_id="alice",
                expires_at=now - timedelta(hours=1),
            )
        )
        store.assign(TemporalRole(role_name="editor", subject_id="alice"))
        assert store.get_active_roles("alice", now) == ["editor"]

    def test_get_active_excludes_future(self):
        now = datetime.now(UTC)
        store = TemporalRoleStore()
        store.assign(
            TemporalRole(
                role_name="admin",
                subject_id="alice",
                effective_from=now + timedelta(hours=1),
            )
        )
        assert store.get_active_roles("alice", now) == []

    def test_revoke(self):
        store = TemporalRoleStore()
        store.assign(TemporalRole(role_name="admin", subject_id="alice"))
        store.assign(TemporalRole(role_name="editor", subject_id="alice"))
        count = store.revoke("admin", "alice")
        assert count == 1
        assert store.get_active_roles("alice") == ["editor"]

    def test_cleanup_expired(self):
        now = datetime.now(UTC)
        store = TemporalRoleStore()
        store.assign(
            TemporalRole(
                role_name="admin",
                subject_id="alice",
                expires_at=now - timedelta(hours=1),
            )
        )
        store.assign(TemporalRole(role_name="editor", subject_id="alice"))
        removed = store.cleanup_expired(now)
        assert removed == 1
        assert store.get_active_roles("alice") == ["editor"]

    def test_different_subjects(self):
        store = TemporalRoleStore()
        store.assign(TemporalRole(role_name="admin", subject_id="alice"))
        store.assign(TemporalRole(role_name="viewer", subject_id="bob"))
        assert store.get_active_roles("alice") == ["admin"]
        assert store.get_active_roles("bob") == ["viewer"]
