import asyncio
import unittest
from unittest.mock import Mock, patch
from fastapi import Request
from analogai.foundation.modules.agent.agent import Agent, Role
from analogai.foundation.modules.user.user import User
from analogai.foundation.extensions.authorization.authorization_factory import AuthorizationFactory
from analogai.foundation.extensions.authorization.core.enums.operation import AuthorizationOperation
from analogai.foundation.extensions.authorization.models import AuthorizationContext

class TestAuthorizationWorkflow(unittest.TestCase):
    def setUp(self):
        self.agent_repository = Mock()
        self.user = User(id="user-123", name="Test User", email="test@example.com")
        self.agent = Agent(
            id="agent-456",
            knowledge_base="kb",
            creator=self.user,
            roles=[Role(user=self.user, authority=0.9)],
        )

    @patch("analogai.foundation.extensions.authorization.authorization_factory.create_repository_strategy")
    @patch("analogai.foundation.extensions.authorization.authorization_factory.AuthenticationFactory")
    def test_authorization_dependency_returns_context_with_role(self, authentication_factory_cls, repository_selector):
        auth_factory = authentication_factory_cls.return_value
        repository_selector.return_value.get_agent_repository.return_value = self.agent_repository

        async def auth_dependency(request: Request) -> User:
            return self.user

        auth_factory.create_authentication_dependency.return_value = auth_dependency
        self.agent_repository.find_by_id.return_value = self.agent

        factory = AuthorizationFactory()
        dependency = factory.create_authorization_dependency()

        request = Mock(spec=Request)
        request.headers = {"Authorization": "Bearer auth-token"}

        context = asyncio.run(dependency(request, agent_id="agent-456"))

        authentication_factory_cls.assert_called_once_with()
        self.agent_repository.find_by_id.assert_called_once_with("agent-456")
        self.assertIsInstance(context, AuthorizationContext)
        self.assertEqual(context.user, self.user)
        self.assertEqual(context.agent, self.agent)
        expected_authority = self.agent.roles[0].authority
        self.assertEqual(context.authority, expected_authority)
        self.assertEqual(context.operation, AuthorizationOperation.CHAT)

    @patch("analogai.foundation.extensions.authorization.authorization_factory.create_repository_strategy")
    @patch("analogai.foundation.extensions.authorization.authorization_factory.AuthenticationFactory")
    def test_authorization_dependency_returns_context_without_role(self, authentication_factory_cls, repository_selector):
        auth_factory = authentication_factory_cls.return_value
        repository_selector.return_value.get_agent_repository.return_value = self.agent_repository
        
        user_without_role = User(id="user-789", name="User Without Role", email="no-role@example.com")
        agent_without_user_role = Agent(
            id="agent-789",
            knowledge_base="kb",
            creator=self.user,
            roles=[Role(user=self.user, authority=0.9)],
        )

        async def auth_dependency(request: Request) -> User:
            return user_without_role

        auth_factory.create_authentication_dependency.return_value = auth_dependency
        self.agent_repository.find_by_id.return_value = agent_without_user_role

        factory = AuthorizationFactory()
        dependency = factory.create_authorization_dependency()

        request = Mock(spec=Request)
        request.headers = {"Authorization": "Bearer auth-token"}

        context = asyncio.run(dependency(request, agent_id="agent-789"))

        self.assertIsInstance(context, AuthorizationContext)
        self.assertEqual(context.user, user_without_role)
        self.assertEqual(context.agent, agent_without_user_role)
        self.assertEqual(context.authority, 0.0)
        self.assertEqual(context.operation, AuthorizationOperation.CHAT)

    @patch("analogai.foundation.extensions.authorization.authorization_factory.create_repository_strategy")
    @patch("analogai.foundation.extensions.authorization.authorization_factory.AuthenticationFactory")
    def test_authority_value_matches_role_authority(self, authentication_factory_cls, repository_selector):
        auth_factory = authentication_factory_cls.return_value
        repository_selector.return_value.get_agent_repository.return_value = self.agent_repository
        
        test_user = User(id="user-test", name="Test User", email="test@example.com")
        test_authority = 0.75
        test_agent = Agent(
            id="agent-test",
            knowledge_base="kb",
            creator=test_user,
            roles=[Role(user=test_user, authority=test_authority)],
        )

        async def auth_dependency(request: Request) -> User:
            return test_user

        auth_factory.create_authentication_dependency.return_value = auth_dependency
        self.agent_repository.find_by_id.return_value = test_agent

        factory = AuthorizationFactory()
        dependency = factory.create_authorization_dependency()

        request = Mock(spec=Request)
        request.headers = {"Authorization": "Bearer auth-token"}

        context = asyncio.run(dependency(request, agent_id="agent-test"))

        user_role = next(role for role in test_agent.roles if role.user.id == test_user.id)
        self.assertEqual(context.authority, user_role.authority)
        self.assertEqual(context.authority, test_authority)

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

