import unittest
from unittest.mock import Mock
from analogai.deepthink.application.usecases.learning.make_direct_statement.usecase import MakeDirectStatementUseCase
from analogai.deepthink.application.usecases.learning.make_direct_statement.states.context.learner_context import LearnerContext
from analogai.deepthink.application.usecases.learning.make_direct_statement.states.context.learner_context_handler import LearnerContextHandler
from analogai.deepthink.application.usecases.learning.make_direct_statement.states.common.response_builder import LearnerResponseBuilder
from analogai.deepthink.application.usecases.learning.make_direct_statement.models import MakeDirectStatementRequest
from analogai.foundation.common.enums import RelationshipType
from analogai.foundation.common.dtos.belief_expression import Relation, Modifier
from analogai.foundation.common.dtos.notion_expression import NotionExpression
from analogai.deepthink.tests.functional.application.usecases.learner.setup import LearnerTestSetup

from analogai.foundation.core.value_objects.time import Time
from analogai.foundation.common.enums.deontic_modality import DeonticModality


class TestLearnerSpatiotemporalFunctional(unittest.TestCase):
    def setUp(self):
        self.setup = LearnerTestSetup()
        self.mock_output_port = self.setup.mock_output_port
        
        context = LearnerContext()
        context_handler = LearnerContextHandler(context, self.setup.notion_service)
        response_builder = LearnerResponseBuilder(context)
        
        self.usecase = MakeDirectStatementUseCase(
            statement_service=self.setup.statement_service,
            notion_service=self.setup.notion_service,
            output_port=self.mock_output_port,
            context_handler=context_handler,
            response_builder=response_builder
        )

    def tearDown(self):
        self.setup.clear()

    def test_learn_statement_with_location(self):
        modifier = Modifier(location="Tbilisi")
        request = MakeDirectStatementRequest(
            user_agent=self.setup.user_agent,
            subject_notion_expression=NotionExpression(caption="it"),
            complement_notion_expression=NotionExpression(caption="rain"),
            relation=Relation.from_type(RelationshipType.DO),
            probability=1.0,
            modifier=modifier
        )
        
        result = self.usecase.execute(request)
        
        self.assertIsNotNone(result)
        self.mock_output_port.mock_output_create_statement_success.assert_called_once()
        call_args = self.mock_output_port.mock_output_create_statement_success.call_args[0][0]
        self.assertIsNotNone(call_args.belief_expression.modifier)
        self.assertEqual(call_args.belief_expression.modifier.location, "Tbilisi")

    def test_learn_statement_with_time(self):
        from_time = Time(year=2024, month=12, day=26)
        modifier = Modifier(from_time=from_time)
        request = MakeDirectStatementRequest(
            user_agent=self.setup.user_agent,
            subject_notion_expression=NotionExpression(caption="it"),
            complement_notion_expression=NotionExpression(caption="rain"),
            relation=Relation.from_type(RelationshipType.DO),
            probability=0.5,
            modifier=modifier
        )
        
        result = self.usecase.execute(request)
        
        self.assertIsNotNone(result)
        self.mock_output_port.mock_output_create_statement_success.assert_called_once()
        call_args = self.mock_output_port.mock_output_create_statement_success.call_args[0][0]
        self.assertIsNotNone(call_args.belief_expression.modifier)
        self.assertIsNotNone(call_args.belief_expression.modifier.from_time)
        self.assertEqual(call_args.belief_expression.modifier.from_time.year, 2024)

    def test_learn_statement_with_time_range(self):
        from_time = Time(year=2024, month=12, day=26, hour=14, minute=0)
        to_time = Time(year=2024, month=12, day=26, hour=16, minute=0)
        modifier = Modifier(from_time=from_time, to_time=to_time)
        request = MakeDirectStatementRequest(
            user_agent=self.setup.user_agent,
            subject_notion_expression=NotionExpression(caption="it"),
            complement_notion_expression=NotionExpression(caption="rain"),
            relation=Relation.from_type(RelationshipType.DO),
            probability=1.0,
            modifier=modifier
        )
        
        result = self.usecase.execute(request)
        
        self.assertIsNotNone(result)
        self.mock_output_port.mock_output_create_statement_success.assert_called_once()
        call_args = self.mock_output_port.mock_output_create_statement_success.call_args[0][0]
        self.assertIsNotNone(call_args.belief_expression.modifier)
        self.assertIsNotNone(call_args.belief_expression.modifier.from_time)
        self.assertIsNotNone(call_args.belief_expression.modifier.to_time)
        self.assertEqual(call_args.belief_expression.modifier.from_time.hour, 14)
        self.assertEqual(call_args.belief_expression.modifier.to_time.hour, 16)

    def test_learn_statement_with_deontic_obligatory(self):
        modifier = Modifier(deontic_modality=DeonticModality.OBLIGATORY)
        request = MakeDirectStatementRequest(
            user_agent=self.setup.user_agent,
            subject_notion_expression=NotionExpression(caption="you"),
            complement_notion_expression=NotionExpression(caption="read socrates"),
            relation=Relation.from_type(RelationshipType.DO),
            probability=1.0,
            modifier=modifier
        )
        
        result = self.usecase.execute(request)
        
        self.assertIsNotNone(result)
        self.mock_output_port.mock_output_create_statement_success.assert_called_once()
        call_args = self.mock_output_port.mock_output_create_statement_success.call_args[0][0]
        self.assertIsNotNone(call_args.belief_expression.modifier)
        self.assertEqual(call_args.belief_expression.modifier.deontic_modality, DeonticModality.OBLIGATORY)

    def test_learn_statement_with_deontic_permitted(self):
        modifier = Modifier(deontic_modality=DeonticModality.PERMITTED)
        request = MakeDirectStatementRequest(
            user_agent=self.setup.user_agent,
            subject_notion_expression=NotionExpression(caption="i"),
            complement_notion_expression=NotionExpression(caption="visit you"),
            relation=Relation.from_type(RelationshipType.DO),
            probability=1.0,
            modifier=modifier
        )
        
        result = self.usecase.execute(request)
        
        self.assertIsNotNone(result)
        self.mock_output_port.mock_output_create_statement_success.assert_called_once()
        call_args = self.mock_output_port.mock_output_create_statement_success.call_args[0][0]
        self.assertIsNotNone(call_args.belief_expression.modifier)
        self.assertEqual(call_args.belief_expression.modifier.deontic_modality, DeonticModality.PERMITTED)

    def test_learn_statement_with_all_parameters(self):
        from_time = Time(year=2024, month=12, day=26, hour=14, minute=0)
        to_time = Time(year=2024, month=12, day=26, hour=16, minute=0)
        modifier = Modifier(
            location="Tbilisi",
            from_time=from_time,
            to_time=to_time,
            deontic_modality=DeonticModality.PERMITTED
        )
        request = MakeDirectStatementRequest(
            user_agent=self.setup.user_agent,
            subject_notion_expression=NotionExpression(caption="i"),
            complement_notion_expression=NotionExpression(caption="visit you"),
            relation=Relation.from_type(RelationshipType.DO),
            probability=1.0,
            modifier=modifier
        )
        
        result = self.usecase.execute(request)
        
        self.assertIsNotNone(result)
        self.mock_output_port.mock_output_create_statement_success.assert_called_once()
        call_args = self.mock_output_port.mock_output_create_statement_success.call_args[0][0]
        self.assertIsNotNone(call_args.belief_expression.modifier)
        self.assertEqual(call_args.belief_expression.modifier.location, "Tbilisi")
        self.assertIsNotNone(call_args.belief_expression.modifier.from_time)
        self.assertIsNotNone(call_args.belief_expression.modifier.to_time)
        self.assertEqual(call_args.belief_expression.modifier.deontic_modality, DeonticModality.PERMITTED)


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


