"""Tests for permission delegation."""

from datetime import UTC, datetime, timedelta

from pyauthz import Delegation, DelegationStore


class TestDelegation:
    def test_active_with_no_bounds(self):
        d = Delegation(grantor_id="alice", grantee_id="bob", permissions=["documents:write"])
        assert d.is_active()

    def test_active_within_window(self):
        now = datetime.now(UTC)
        d = Delegation(
            grantor_id="alice",
            grantee_id="bob",
            permissions=["documents:write"],
            effective_from=now - timedelta(hours=1),
            expires_at=now + timedelta(hours=1),
        )
        assert d.is_active(now)

    def test_expired(self):
        now = datetime.now(UTC)
        d = Delegation(
            grantor_id="alice",
            grantee_id="bob",
            permissions=["documents:write"],
            expires_at=now - timedelta(hours=1),
        )
        assert not d.is_active(now)

    def test_not_yet_effective(self):
        now = datetime.now(UTC)
        d = Delegation(
            grantor_id="alice",
            grantee_id="bob",
            permissions=["documents:write"],
            effective_from=now + timedelta(hours=1),
        )
        assert not d.is_active(now)

    def test_created_at_auto_set(self):
        d = Delegation(grantor_id="alice", grantee_id="bob", permissions=["documents:write"])
        assert d.created_at is not None


class TestDelegationStore:
    def test_create_and_get_permissions(self):
        store = DelegationStore()
        store.create(
            Delegation(
                grantor_id="alice",
                grantee_id="bob",
                permissions=["documents:write", "documents:read"],
            )
        )
        perms = store.get_active_permissions("bob")
        assert sorted(perms) == ["documents:read", "documents:write"]

    def test_get_permissions_excludes_expired(self):
        now = datetime.now(UTC)
        store = DelegationStore()
        store.create(
            Delegation(
                grantor_id="alice",
                grantee_id="bob",
                permissions=["documents:write"],
                expires_at=now - timedelta(hours=1),
            )
        )
        store.create(
            Delegation(
                grantor_id="carol",
                grantee_id="bob",
                permissions=["documents:read"],
            )
        )
        assert store.get_active_permissions("bob", now) == ["documents:read"]

    def test_revoke(self):
        store = DelegationStore()
        store.create(
            Delegation(grantor_id="alice", grantee_id="bob", permissions=["documents:write"])
        )
        count = store.revoke("alice", "bob")
        assert count == 1
        assert store.get_active_permissions("bob") == []

    def test_get_by_grantor(self):
        store = DelegationStore()
        store.create(
            Delegation(grantor_id="alice", grantee_id="bob", permissions=["documents:write"])
        )
        store.create(
            Delegation(grantor_id="alice", grantee_id="carol", permissions=["documents:read"])
        )
        delegations = store.get_delegations_by_grantor("alice")
        assert len(delegations) == 2

    def test_get_by_grantee(self):
        store = DelegationStore()
        store.create(
            Delegation(grantor_id="alice", grantee_id="bob", permissions=["documents:write"])
        )
        store.create(
            Delegation(grantor_id="carol", grantee_id="bob", permissions=["documents:read"])
        )
        delegations = store.get_delegations_by_grantee("bob")
        assert len(delegations) == 2

    def test_cleanup_expired(self):
        now = datetime.now(UTC)
        store = DelegationStore()
        store.create(
            Delegation(
                grantor_id="alice",
                grantee_id="bob",
                permissions=["documents:write"],
                expires_at=now - timedelta(hours=1),
            )
        )
        store.create(
            Delegation(grantor_id="carol", grantee_id="bob", permissions=["documents:read"])
        )
        removed = store.cleanup_expired(now)
        assert removed == 1
        assert len(store.get_delegations_by_grantee("bob")) == 1

    def test_reason_field(self):
        d = Delegation(
            grantor_id="alice",
            grantee_id="bob",
            permissions=["documents:write"],
            reason="Covering while OOO",
        )
        assert d.reason == "Covering while OOO"
