# Phase 1 verified
import unittest
from unittest.mock import MagicMock, patch
import hashlib
from hieromem_api.errors import UnauthorizedError

from hieromem_api.tenants import Tenant, InMemoryTenantRegistry
from hieromem_api.auth import require_api_key, _hash_key


class TestAuthHashing(unittest.TestCase):
    def setUp(self) -> None:
        self.registry = InMemoryTenantRegistry()
        # Patch the registry getter to return our local registry
        self.patcher = patch(
            "hieromem_api.auth.get_tenant_registry",
            return_value=self.registry)
        self.patcher.start()

    def tearDown(self) -> None:
        self.patcher.stop()

    def test_hashing_function(self) -> None:
        key = "sk-test-123"
        expected_hash = hashlib.sha256(key.encode("utf-8")).hexdigest()
        self.assertEqual(_hash_key(key), expected_hash)

    def test_registry_storage_and_retrieval(self) -> None:
        key = "sk-secret-key"
        key_hash = _hash_key(key)

        tenant = Tenant(tenant_id="user1", api_key=key, api_key_hash=key_hash)
        self.registry.upsert(tenant)

        # Should find by hash
        found = self.registry.get_by_hash(key_hash)
        if found is None:
            self.fail("Expected tenant to be retrievable by hashed API key")
        self.assertEqual(found.tenant_id, "user1")

        # Should not find by raw key
        not_found = self.registry.get_by_hash(key)
        self.assertIsNone(not_found)

    def test_require_api_key_success(self) -> None:
        key = "sk-valid-key"
        key_hash = _hash_key(key)
        tenant = Tenant(tenant_id="valid-user", api_key=key, api_key_hash=key_hash)
        self.registry.upsert(tenant)

        # Mock request
        request = MagicMock()
        request.state = MagicMock()

        # Call auth function with raw key
        result_tenant = require_api_key(request, x_api_key=key)

        self.assertEqual(result_tenant.tenant_id, "valid-user")
        self.assertEqual(request.state.tenant_id, "valid-user")

    def test_require_api_key_failure(self) -> None:
        # Mock request
        request = MagicMock()

        # Call with invalid key - now raises UnauthorizedError
        with self.assertRaises(UnauthorizedError) as cm:
            require_api_key(request, x_api_key="sk-invalid")

        self.assertEqual(cm.exception.status_code, 401)


if __name__ == "__main__":
    unittest.main()
