"""Unit tests for MWT creation, decoding, and permission key derivation."""

from unittest import TestCase
from unittest.mock import MagicMock

from mizan_core.mwt import (
    MWTUser,
    compute_permission_key,
    create_mwt,
    decode_mwt,
)


def _make_user(**kwargs):
    user = MagicMock()
    user.pk = kwargs.get("pk", 1)
    user.is_staff = kwargs.get("is_staff", False)
    user.is_superuser = kwargs.get("is_superuser", False)
    user.get_all_permissions = MagicMock(return_value=kwargs.get("perms", set()))
    return user


class MWTCreationTests(TestCase):
    """Tests for MWT creation and decoding."""

    SECRET = "test-mwt-secret-that-is-32bytes!"

    def test_create_and_decode(self):
        """Create an MWT and decode it successfully."""
        user = _make_user(pk=42, is_staff=True)
        token = create_mwt(user, self.SECRET, ttl=300)
        payload = decode_mwt(token, self.SECRET)

        self.assertIsNotNone(payload)
        self.assertEqual(payload.sub, "42")
        self.assertTrue(payload.staff)
        self.assertFalse(payload.super)
        self.assertEqual(payload.kid, "v1")
        self.assertEqual(len(payload.pkey), 64)

    def test_decode_expired(self):
        """Expired MWT returns None."""
        user = _make_user()
        token = create_mwt(user, self.SECRET, ttl=-1)
        payload = decode_mwt(token, self.SECRET)
        self.assertIsNone(payload)

    def test_decode_wrong_secret(self):
        """MWT signed with wrong secret returns None."""
        user = _make_user()
        token = create_mwt(user, self.SECRET)
        payload = decode_mwt(token, "wrong-secret")
        self.assertIsNone(payload)

    def test_decode_wrong_audience(self):
        """MWT with wrong audience returns None."""
        user = _make_user()
        token = create_mwt(user, self.SECRET, audience="app1")
        payload = decode_mwt(token, self.SECRET, audience="app2")
        self.assertIsNone(payload)

    def test_mwt_user_has_pkey(self):
        """MWTUser carries the permission key."""
        user = _make_user(pk=5, perms={"app.view_thing"})
        token = create_mwt(user, self.SECRET)
        payload = decode_mwt(token, self.SECRET)
        mwt_user = MWTUser(payload)

        self.assertEqual(mwt_user.pk, 5)
        self.assertTrue(mwt_user.is_authenticated)
        self.assertEqual(len(mwt_user.pkey), 64)


class PermissionKeyTests(TestCase):
    """Tests for pkey determinism and sensitivity."""

    def test_deterministic(self):
        """Same permissions produce same pkey."""
        user = _make_user(perms={"app.view_thing", "app.add_thing"})
        pkey1 = compute_permission_key(user)
        pkey2 = compute_permission_key(user)
        self.assertEqual(pkey1, pkey2)

    def test_changes_on_permission_change(self):
        """Different permissions produce different pkey."""
        user1 = _make_user(perms={"app.view_thing"})
        user2 = _make_user(perms={"app.view_thing", "app.add_thing"})
        self.assertNotEqual(compute_permission_key(user1), compute_permission_key(user2))

    def test_changes_on_staff_change(self):
        """Staff status change produces different pkey."""
        user_normal = _make_user(is_staff=False)
        user_staff = _make_user(is_staff=True)
        self.assertNotEqual(
            compute_permission_key(user_normal),
            compute_permission_key(user_staff),
        )
