import unittest
from datetime import datetime, timedelta
from types import SimpleNamespace
from unittest.mock import Mock

from analogai.foundation.common.enums import RelationshipType
from analogai.foundation.core.value_objects import Relation
from analogai.foundation.core.value_objects.modifier import Modifier
from analogai.foundation.core.value_objects.time import Time
from analogai.foundation.common.design_patterns.state_machine import State
from analogai.deepthink.application.usecases.learning.make_direct_statement.states.find_statement_state import FindStatementState
from analogai.deepthink.application.usecases.learning.make_direct_statement.usecase import MakeDirectStatementUseCase

class TestFindStatementState(unittest.TestCase):
    def setUp(self):
        self.state_machine = Mock(spec=MakeDirectStatementUseCase)
        self.statement_service = Mock()
        self.context = Mock(spec=['subject_notion', 'complement_notion', 'relation', 'user_agent', 'modifier', 'statement'])
        self.state_machine.context = self.context
        self.find_statement_state = FindStatementState(self.state_machine, self.statement_service)

    def test_init(self):
        self.assertEqual(self.find_statement_state.state_machine, self.state_machine)
        self.assertEqual(self.find_statement_state._statement_service, self.statement_service)
        self.assertIsInstance(self.find_statement_state, State)

    def test_execute_statement_found(self):
        statement = Mock()
        self.find_statement_state._find_statement = Mock(return_value=statement)
        self.find_statement_state._transition = Mock(return_value="next_state")
        
        result = self.find_statement_state.execute()
        
        self.find_statement_state._find_statement.assert_called_once()
        self.find_statement_state._transition.assert_called_once_with(statement)
        self.assertEqual(result, "next_state")

    def test_execute_no_statement(self):
        self.find_statement_state._find_statement = Mock(return_value=None)
        self.find_statement_state._transition = Mock(return_value="next_state")
        
        result = self.find_statement_state.execute()
        
        self.find_statement_state._find_statement.assert_called_once()
        self.find_statement_state._transition.assert_called_once_with(None)
        self.assertEqual(result, "next_state")

    def test_find_statement_success(self):
        statement = Mock()
        statement.modifier = None
        self.context.subject_notion = "source"
        self.context.complement_notion = "target"
        self.context.relation = Relation.from_type(RelationshipType.IS_A)
        self.context.user_agent = Mock()
        self.context.user_agent.user_id = "user"
        self.context.modifier = None
        self.statement_service.find.return_value = statement
        
        result = self.find_statement_state._find_statement()
        
        self.statement_service.find.assert_called_once_with(
            subject_notion="source",
            complement_notion="target",
            relation=self.context.relation,
            modifier=None
        )
        self.assertEqual(self.context.statement, statement)
        self.assertEqual(result, statement)

    def test_find_statement_none(self):
        test_relation = Relation.from_type(RelationshipType.IS_A)
        context = SimpleNamespace(
            subject_notion="source",
            complement_notion="target",
            relation=test_relation,
            user_agent=Mock(),
            modifier=None,
        )
        context.user_agent.user_id = "user"
        self.state_machine.context = context
        self.statement_service.find.return_value = None

        result = self.find_statement_state._find_statement()

        self.statement_service.find.assert_called_once_with(
            subject_notion="source",
            complement_notion="target",
            relation=test_relation,
            modifier=None
        )
        with self.assertRaises(AttributeError):
            _ = context.statement
        self.assertIsNone(result)

    def test_find_statement_with_mismatched_modifier_returns_none(self):
        today = datetime.now()
        tomorrow = today + timedelta(days=1)

        statement = Mock()
        statement.modifier = Modifier(from_time=Time(year=today.year, month=today.month, day=today.day))

        context = SimpleNamespace(
            subject_notion="source",
            complement_notion="target",
            relation=Relation.from_type(RelationshipType.IS_A),
            user_agent=Mock(),
            modifier=Modifier(from_time=Time(year=tomorrow.year, month=tomorrow.month, day=tomorrow.day)),
        )
        context.user_agent.user_id = "user"
        self.state_machine.context = context
        self.statement_service.find.return_value = statement

        result = self.find_statement_state._find_statement()

        self.statement_service.find.assert_called_once()
        self.assertIsNone(result)
        with self.assertRaises(AttributeError):
            _ = context.statement

    def test_find_statement_with_matching_modifier_returns_statement(self):
        today = datetime.now()
        modifier = Modifier(from_time=Time(year=today.year, month=today.month, day=today.day))
        
        statement = Mock()
        statement.modifier = modifier
        
        self.context.subject_notion = "source"
        self.context.complement_notion = "target"
        self.context.relation = Relation.from_type(RelationshipType.IS_A)
        self.context.user_agent = Mock()
        self.context.user_agent.user_id = "user"
        self.context.modifier = modifier
        self.statement_service.find.return_value = statement
        
        result = self.find_statement_state._find_statement()
        
        self.statement_service.find.assert_called_once()
        self.assertEqual(self.context.statement, statement)
        self.assertEqual(result, statement)

    def test_transition_no_statement(self):
        self.state_machine.state_to_create_statement.return_value = "create_state"
        
        result = self.find_statement_state._transition(None)
        
        self.state_machine.state_to_create_statement.assert_called_once()
        self.assertEqual(result, "create_state")

    def test_transition_statement_found(self):
        statement = Mock()
        self.state_machine.state_to_update_statement.return_value = "update_state"

        result = self.find_statement_state._transition(statement)

        self.state_machine.state_to_update_statement.assert_called_once()
        self.assertEqual(result, "update_state")

    def test_transition_to_create(self):
        self.state_machine.state_to_create_statement.return_value = "create_state"

        result = self.find_statement_state._transition_to_create()

        self.state_machine.state_to_create_statement.assert_called_once()
        self.assertEqual(result, "create_state")

    def test_transition_to_check_update_applicable(self):
        self.state_machine.state_to_update_statement.return_value = "update_state"

        result = self.find_statement_state._transition_to_check_update_applicable()

        self.state_machine.state_to_update_statement.assert_called_once()
        self.assertEqual(result, "update_state")

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



