import unittest
from unittest.mock import Mock, patch
from analogai.foundation.modules.user.user import User
from analogai.foundation.modules.user.user_service import UserService
from analogai.foundation.extensions.authentication.providers.auth0 import Auth0JWTService
from analogai.foundation.extensions.authentication.models import TokenPayload

class TestAuth0JWTService(unittest.TestCase):
    def setUp(self):
        self.user_service = Mock(spec=UserService)
        self.jwt_service = Auth0JWTService(self.user_service)
        self.user = User(id="test-user-123", name="Test User", email="test@example.com")

    def test_create_token_for_user(self):
        self.user_service.find.return_value = self.user
        with patch("analogai.foundation.extensions.authentication.providers.auth0.auth0_jwt_service.jwt.encode") as mock_encode:
            mock_encode.return_value = "mock.jwt.token"
            token = self.jwt_service.create_token_for_user(self.user.id)
            self.assertEqual(token, "mock.jwt.token")
            payload = mock_encode.call_args[0][0]
            self.assertEqual(payload["sub"], "analogai|test-user-123")
            self.assertEqual(payload["email"], "test@example.com")

    def test_create_token_for_user_missing_email(self):
        user_without_email = User(id="no-email", name="No Email", email=None)
        self.user_service.find.return_value = user_without_email
        with self.assertRaises(ValueError):
            self.jwt_service.create_token_for_user(user_without_email.id)

    def test_authenticate_user_success(self):
        self.user_service.find_by_email.return_value = self.user
        with patch.object(self.jwt_service, "extract_payload") as mock_extract:
            mock_extract.return_value = TokenPayload(token="t", email=self.user.email)
            result = self.jwt_service.authenticate_user("valid.token")
            self.assertEqual(result, self.user)

    def test_authenticate_user_no_user(self):
        self.user_service.find_by_email.return_value = None
        with patch.object(self.jwt_service, "extract_payload") as mock_extract:
            mock_extract.return_value = TokenPayload(token="t", email="missing@example.com")
            with self.assertRaises(ValueError):
                self.jwt_service.authenticate_user("valid.token")

    def test_authenticate_user_invalid_token(self):
        with patch.object(self.jwt_service, "extract_payload") as mock_extract:
            mock_extract.side_effect = ValueError("Invalid token format")
            with self.assertRaises(ValueError):
                self.jwt_service.authenticate_user("invalid.token")

    def test_extract_payload_success(self):
        mock_payload = {"email": "test@example.com", "sub": "auth0|user-123", "name": "Tester"}
        self.user_service.find_by_email.return_value = self.user
        with patch("analogai.foundation.extensions.authentication.providers.auth0.auth0_jwt_service.jwt.decode") as mock_decode:
            mock_decode.return_value = mock_payload
            payload = self.jwt_service.extract_payload("valid.token")
            self.assertEqual(payload.email, "test@example.com")
            self.assertEqual(payload.user_id, "test-user-123")
            self.assertEqual(payload.name, "Test User")
            self.assertEqual(payload.provider, "auth0")

    def test_extract_payload_missing_email(self):
        mock_payload = {"sub": "auth0|user-123"}
        with patch("analogai.foundation.extensions.authentication.providers.auth0.auth0_jwt_service.jwt.decode") as mock_decode:
            mock_decode.return_value = mock_payload
            with self.assertRaises(ValueError):
                self.jwt_service.extract_payload("valid.token")

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

