import unittest
from unittest.mock import Mock
from analogai.foundation.core.value_objects.modifier import Modifier
from analogai.foundation.common.utils.modifier_utils import ModifierMatcher
from analogai.foundation.modules.direct_statement.direct_statement import DirectStatement as Statement
from analogai.foundation.core.value_objects.time import Time
from analogai.foundation.core.value_objects.relation import Relation
from analogai.foundation.common.enums.deontic_modality import DeonticModality
from analogai.foundation.modules.notion.notion import Notion

class TestModifierMatcher(unittest.TestCase):
    
    def setUp(self):
        self.matcher = ModifierMatcher()
        self.subject_notion = Notion(user_id="user1", agent_id="agent1", caption="Source", id="source1")
        self.complement_notion = Notion(user_id="user1", agent_id="agent1", caption="Target", id="target1")
    
    def create_statement(self, location=None, from_time=None, to_time=None, deontic_modality=None):
        modifier = None
        if any([location, from_time, to_time, deontic_modality]):
            from analogai.foundation.common.utils.modifier_utils import ModifierBuilder
            builder = ModifierBuilder()
            if location:
                builder.with_location(location)
            if from_time:
                builder.with_from_time(
                    year=from_time.year,
                    month=from_time.month,
                    day=from_time.day,
                    hour=from_time.hour,
                    minute=from_time.minute
                )
            if to_time:
                builder.with_to_time(
                    year=to_time.year,
                    month=to_time.month,
                    day=to_time.day,
                    hour=to_time.hour,
                    minute=to_time.minute
                )
            if deontic_modality:
                builder.with_deontic_modality(deontic_modality)
            modifier = builder.build()
        return Statement(
            user_id="user1",
            agent_id="agent1",
            subject_notion=self.subject_notion,
            relation=Relation.from_string("is"),
            complement_notion=self.complement_notion,
            probability=0.8,
            validity=0.9,
            modifier=modifier
        )
    
    def test_matches_empty_context(self):
        statement = self.create_statement(location="New York")
        context = Modifier()
        
        result = self.matcher.matches(statement, context)
        
        self.assertTrue(result)
    
    def test_matches_location(self):
        statement = self.create_statement(location="New York")
        context = Modifier(location="New York")
        
        result = self.matcher.matches(statement, context)
        
        self.assertTrue(result)
    
    def test_does_not_match_location(self):
        statement = self.create_statement(location="New York")
        context = Modifier(location="London")
        
        result = self.matcher.matches(statement, context)
        
        self.assertFalse(result)
    
    def test_matches_deontic_modality(self):
        statement = self.create_statement(deontic_modality=DeonticModality.OBLIGATORY)
        context = Modifier(deontic_modality=DeonticModality.OBLIGATORY)
        
        result = self.matcher.matches(statement, context)
        
        self.assertTrue(result)
    
    def test_does_not_match_mismatched_deontic_modality(self):
        statement = self.create_statement(deontic_modality=DeonticModality.OBLIGATORY)
        context = Modifier(deontic_modality=DeonticModality.PERMITTED)
        
        result = self.matcher.matches(statement, context)
        
        self.assertFalse(result, "Statement with different deontic modality should not match")
    
    def test_does_not_match_when_search_has_deontic_but_statement_does_not(self):
        statement = self.create_statement()
        context = Modifier(deontic_modality=DeonticModality.OBLIGATORY)
        
        result = self.matcher.matches(statement, context)
        
        self.assertFalse(result, "Statement without deontic modality should not match search with deontic modality")
    
    def test_matches_when_search_has_no_deontic_but_statement_has_deontic(self):
        statement = self.create_statement(deontic_modality=DeonticModality.OBLIGATORY)
        context = Modifier()
        
        result = self.matcher.matches(statement, context)
        
        self.assertTrue(result, "Statement with deontic modality should match search without deontic modality")
    
    def test_matches_from_time_exact(self):
        from_time = Time(year=2024, month=1, day=1)
        statement = self.create_statement(from_time=from_time)
        context = Modifier(from_time=Time(year=2024, month=1, day=1))
        
        result = self.matcher.matches(statement, context)
        
        self.assertTrue(result)
    
    def test_matches_from_time_partial(self):
        from_time = Time(year=2024, month=1, day=1, hour=10)
        statement = self.create_statement(from_time=from_time)
        context = Modifier(from_time=Time(year=2024, month=1))
        
        result = self.matcher.matches(statement, context)
        
        self.assertTrue(result)
    
    def test_does_not_match_from_time(self):
        from_time = Time(year=2024, month=1, day=1)
        statement = self.create_statement(from_time=from_time)
        context = Modifier(from_time=Time(year=2024, month=2))
        
        result = self.matcher.matches(statement, context)
        
        self.assertFalse(result)
    
    def test_does_not_match_from_time_when_statement_has_none(self):
        statement = self.create_statement()
        context = Modifier(from_time=Time(year=2024))
        
        result = self.matcher.matches(statement, context)
        
        self.assertFalse(result)
    
    def test_matches_to_time_exact(self):
        to_time = Time(year=2024, month=12, day=31)
        statement = self.create_statement(to_time=to_time)
        context = Modifier(to_time=Time(year=2024, month=12, day=31))
        
        result = self.matcher.matches(statement, context)
        
        self.assertTrue(result)
    
    def test_matches_multiple_context(self):
        from_time = Time(year=2024, month=1)
        statement = self.create_statement(
            location="New York",
            from_time=from_time,
            deontic_modality=DeonticModality.OBLIGATORY
        )
        context = Modifier(
            location="New York",
            from_time=Time(year=2024, month=1),
            deontic_modality=DeonticModality.OBLIGATORY
        )
        
        result = self.matcher.matches(statement, context)
        
        self.assertTrue(result)
    
    def test_does_not_match_when_one_criterion_fails(self):
        from_time = Time(year=2024, month=1)
        statement = self.create_statement(
            location="New York",
            from_time=from_time,
            deontic_modality=DeonticModality.OBLIGATORY
        )
        context = Modifier(
            location="New York",
            from_time=Time(year=2024, month=2),
            deontic_modality=DeonticModality.OBLIGATORY
        )
        
        result = self.matcher.matches(statement, context)
        
        self.assertFalse(result)

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