"""Unit tests for cache key derivation. Includes the cross-language pin against mizan-ts."""

from unittest import TestCase

from mizan_core.cache.keys import derive_cache_key


class CacheKeyDerivationTests(TestCase):
    """Tests that HMAC cache key derivation is deterministic and correct."""

    SECRET = "test-cache-secret"

    def test_deterministic_output(self):
        """Same inputs always produce the same key."""
        key1 = derive_cache_key(self.SECRET, "user", {"user_id": "5"})
        key2 = derive_cache_key(self.SECRET, "user", {"user_id": "5"})
        self.assertEqual(key1, key2)
        self.assertTrue(key1.startswith("ctx:user:"))
        self.assertEqual(len(key1), len("ctx:user:") + 64)  # prefix + SHA-256 hex

    def test_param_order_irrelevant(self):
        """Parameter ordering does not affect the key."""
        key1 = derive_cache_key(self.SECRET, "ctx", {"a": "1", "b": "2"})
        key2 = derive_cache_key(self.SECRET, "ctx", {"b": "2", "a": "1"})
        self.assertEqual(key1, key2)

    def test_different_user_ids_different_keys(self):
        """Different user_ids produce different cache keys."""
        key1 = derive_cache_key(self.SECRET, "user", {"user_id": "5"}, user_id="5")
        key2 = derive_cache_key(self.SECRET, "user", {"user_id": "5"}, user_id="6")
        self.assertNotEqual(key1, key2)

    def test_rev_changes_key(self):
        """Different rev values produce different cache keys."""
        key1 = derive_cache_key(self.SECRET, "user", {"user_id": "5"}, rev=0)
        key2 = derive_cache_key(self.SECRET, "user", {"user_id": "5"}, rev=1)
        self.assertNotEqual(key1, key2)

    def test_no_delimiter_collision(self):
        """JSON-canonical form prevents delimiter-free concatenation collisions."""
        # "user" + user_id="12" + params="3" vs "user1" + user_id="2" + params="3"
        key1 = derive_cache_key(self.SECRET, "user", {"id": "3"}, user_id="12")
        key2 = derive_cache_key(self.SECRET, "user1", {"id": "3"}, user_id="2")
        self.assertNotEqual(key1, key2)

    def test_public_vs_user_scoped(self):
        """Public (no user_id) and user-scoped produce different keys."""
        public = derive_cache_key(self.SECRET, "products", {"id": "1"})
        scoped = derive_cache_key(self.SECRET, "products", {"id": "1"}, user_id="5")
        self.assertNotEqual(public, scoped)

    def test_cross_language_pin(self):
        """Pinned HMAC values — must match TypeScript adapter exactly."""
        pin_secret = "test-pin-secret-that-is-32bytes!"

        public_key = derive_cache_key(pin_secret, "user", {"user_id": "5"}, rev=0)
        self.assertEqual(
            public_key,
            "ctx:user:605a1ca5ad5994e9b765c8d1b330474c2a0d51a7b8fbbdc402f992da7ba902f6",
        )

        user_scoped_key = derive_cache_key(
            pin_secret, "user", {"user_id": "5"}, user_id="5", rev=0,
        )
        self.assertEqual(
            user_scoped_key,
            "ctx:user:30fc08eb46ee4ff2cf7d317e97dca90fd616511e0587304416f71dc863338dc2",
        )
