from unittest import TestCase
import unittest
from analogai.foundation.modules.notion.notion import Notion
from analogai.foundation.core.value_objects.modifier import Modifier
from analogai.foundation.core.value_objects.relation import Relation
from analogai.foundation.common.utils.modifier_utils import ModifierBuilder
from analogai.foundation.core.value_objects.time import Time
from analogai.foundation.common.enums.deontic_modality import DeonticModality
from analogai.foundation.tests.functional.services.setup import ServicesTestConfig

class TestBeliefServiceModifierFunctional(TestCase):
    def setUp(self):
        self.config = ServicesTestConfig()
        self.user = self.config.user
        self.agent = self.config.agent
        self.belief_service = self.config.belief_service
        self.statement_service = self.config.statement_service
        self.subject_notion = Notion(user_id=self.user.id, agent_id=self.agent.id, caption="human", id="human_id")
        self.complement_notion = Notion(user_id=self.user.id, agent_id=self.agent.id, caption="mortal", id="mortal_id")
        self.config.notion_repository.create(self.subject_notion)
        self.config.notion_repository.create(self.complement_notion)

    def tearDown(self):
        self.config.tear_down()

    def test_belief_preserves_modifier_through_storage(self):
        modifier = Modifier(
            location="Berlin",
            from_time=Time(year=2024, month=6, day=15),
            to_time=Time(year=2024, month=12, day=31),
            deontic_modality=DeonticModality.PERMITTED
        )
        self.statement_service.create(
            user_id=self.user.id,
            agent_id=self.agent.id,
            subject_notion=self.subject_notion,
            complement_notion=self.complement_notion,
            relation=Relation.from_string("is"),
            probability=0.8,
            validity=0.9,
            modifier=modifier
        )
        belief = self.belief_service.find(
            self.subject_notion, self.complement_notion, Relation.from_string("is"),
            modifier=modifier
        )
        self.assertIsNotNone(belief)
        self.assertEqual(belief.location, "Berlin")
        self.assertIsNotNone(belief.from_time)
        self.assertEqual(belief.from_time.year, 2024)
        self.assertEqual(belief.from_time.month, 6)
        self.assertEqual(belief.from_time.day, 15)
        self.assertIsNotNone(belief.to_time)
        self.assertEqual(belief.to_time.year, 2024)
        self.assertEqual(belief.to_time.month, 12)
        self.assertEqual(belief.deontic_modality, DeonticModality.PERMITTED)
        retrieved_belief = self.belief_service.find(
            self.subject_notion, self.complement_notion, Relation.from_string("is"),
            modifier=modifier
        )
        self.assertIsNotNone(retrieved_belief)
        if retrieved_belief is None:
            self.fail("Expected belief to be found")
        self.assertEqual(retrieved_belief.location, "Berlin")
        self.assertEqual(retrieved_belief.deontic_modality, DeonticModality.PERMITTED)

    def test_search_beliefs_by_modifier_location(self):
        statement1 = self.statement_service.create(
            user_id=self.user.id,
            agent_id=self.agent.id,
            subject_notion=self.subject_notion,
            complement_notion=self.complement_notion,
            relation=Relation.from_string("is"),
            probability=0.8,
            validity=0.9,
            modifier=Modifier(location="Vienna")
        )
        other_notion = Notion(user_id=self.user.id, agent_id=self.agent.id, caption="animal", id="animal_id")
        self.config.notion_repository.create(other_notion)
        statement2 = self.statement_service.create(
            user_id=self.user.id,
            agent_id=self.agent.id,
            subject_notion=self.subject_notion,
            complement_notion=other_notion,
            relation=Relation.from_string("is"),
            probability=0.7,
            validity=0.85,
            modifier=Modifier(location="Prague")
        )
        results = self.belief_service.search_by_subject_notion(
            self.subject_notion,
            modifier=Modifier(location="Vienna")
        )
        self.assertEqual(len(results), 1)
        self.assertEqual(results[0].location, "Vienna")
        self.assertEqual(len(results[0].statements), 1)
        self.assertEqual(results[0].statements[0].id, statement1.id)

    def test_search_beliefs_by_modifier_deontic_modality(self):
        self.statement_service.create(
            user_id=self.user.id,
            agent_id=self.agent.id,
            subject_notion=self.subject_notion,
            complement_notion=self.complement_notion,
            relation=Relation.from_string("is"),
            probability=0.8,
            validity=0.9,
            modifier=Modifier(deontic_modality=DeonticModality.OBLIGATORY)
        )
        other_notion = Notion(user_id=self.user.id, agent_id=self.agent.id, caption="animal", id="animal_id")
        self.config.notion_repository.create(other_notion)
        self.statement_service.create(
            user_id=self.user.id,
            agent_id=self.agent.id,
            subject_notion=self.subject_notion,
            complement_notion=other_notion,
            relation=Relation.from_string("is"),
            probability=0.7,
            validity=0.85,
            modifier=Modifier(deontic_modality=DeonticModality.PERMITTED)
        )
        results = self.belief_service.search_by_subject_notion(
            self.subject_notion,
            modifier=Modifier(deontic_modality=DeonticModality.OBLIGATORY)
        )
        self.assertEqual(len(results), 1, "Deontic modality filtering should return matching beliefs")
        result_ids = {r.id for r in results}
        statement1_belief = self.belief_service.find(
            self.subject_notion, self.complement_notion, Relation.from_string("is"),
            modifier=Modifier(deontic_modality=DeonticModality.OBLIGATORY)
        )
        statement2_belief = self.belief_service.find(
            self.subject_notion, other_notion, Relation.from_string("is"),
            modifier=Modifier(deontic_modality=DeonticModality.PERMITTED)
        )
        self.assertIn(statement1_belief.id, result_ids)
        self.assertNotIn(statement2_belief.id, result_ids)

    def test_search_beliefs_by_modifier_time(self):
        from_time = Time(year=2024, month=3, day=1)
        statement1 = self.statement_service.create(
            user_id=self.user.id,
            agent_id=self.agent.id,
            subject_notion=self.subject_notion,
            complement_notion=self.complement_notion,
            relation=Relation.from_string("is"),
            probability=0.8,
            validity=0.9,
            modifier=Modifier(from_time=from_time)
        )
        other_notion = Notion(user_id=self.user.id, agent_id=self.agent.id, caption="animal", id="animal_id")
        self.config.notion_repository.create(other_notion)
        statement2 = self.statement_service.create(
            user_id=self.user.id,
            agent_id=self.agent.id,
            subject_notion=self.subject_notion,
            complement_notion=other_notion,
            relation=Relation.from_string("is"),
            probability=0.7,
            validity=0.85,
            modifier=Modifier(from_time=Time(year=2024, month=6))
        )
        results = self.belief_service.search_by_subject_notion(
            self.subject_notion,
            modifier=Modifier(from_time=Time(year=2024, month=3))
        )
        self.assertEqual(len(results), 1)
        self.assertIsNotNone(results[0].from_time)
        self.assertEqual(results[0].from_time.year, 2024)
        self.assertEqual(results[0].from_time.month, 3)
        self.assertEqual(len(results[0].statements), 1)
        self.assertEqual(results[0].statements[0].id, statement1.id)

    def test_search_beliefs_by_modifier_location_and_time(self):
        statement1 = self.statement_service.create(
            user_id=self.user.id,
            agent_id=self.agent.id,
            subject_notion=self.subject_notion,
            complement_notion=self.complement_notion,
            relation=Relation.from_string("is"),
            probability=0.8,
            validity=0.9,
            modifier=Modifier(location="Lisbon", from_time=Time(year=2024, month=4))
        )
        other_notion = Notion(user_id=self.user.id, agent_id=self.agent.id, caption="animal", id="animal_id")
        self.config.notion_repository.create(other_notion)
        self.statement_service.create(
            user_id=self.user.id,
            agent_id=self.agent.id,
            subject_notion=self.subject_notion,
            complement_notion=other_notion,
            relation=Relation.from_string("is"),
            probability=0.7,
            validity=0.85,
            modifier=Modifier(location="Lisbon", from_time=Time(year=2024, month=5))
        )
        self.statement_service.create(
            user_id=self.user.id,
            agent_id=self.agent.id,
            subject_notion=self.subject_notion,
            complement_notion=other_notion,
            relation=Relation.from_string("is"),
            probability=0.7,
            validity=0.85,
            modifier=Modifier(location="Porto", from_time=Time(year=2024, month=4))
        )

        results = self.belief_service.search_by_subject_notion(
            self.subject_notion,
            modifier=Modifier(location="Lisbon", from_time=Time(year=2024, month=4))
        )

        self.assertEqual(len(results), 1)
        self.assertEqual(results[0].location, "Lisbon")
        self.assertIsNotNone(results[0].from_time)
        self.assertEqual(results[0].from_time.month, 4)
        self.assertEqual(len(results[0].statements), 1)
        self.assertEqual(results[0].statements[0].id, statement1.id)

    def test_search_beliefs_by_modifier_multiple_properties(self):
        self.statement_service.create(
            user_id=self.user.id,
            agent_id=self.agent.id,
            subject_notion=self.subject_notion,
            complement_notion=self.complement_notion,
            relation=Relation.from_string("is"),
            probability=0.8,
            validity=0.9,
            modifier=ModifierBuilder()
                .with_location("Madrid")
                .with_deontic_modality(DeonticModality.FORBIDDEN)
                .with_from_time(year=2024, month=5)
                .build()
        )
        other_notion = Notion(user_id=self.user.id, agent_id=self.agent.id, caption="animal", id="animal_id")
        self.config.notion_repository.create(other_notion)
        self.statement_service.create(
            user_id=self.user.id,
            agent_id=self.agent.id,
            subject_notion=self.subject_notion,
            complement_notion=other_notion,
            relation=Relation.from_string("is"),
            probability=0.7,
            validity=0.85,
            modifier=ModifierBuilder()
                .with_location("Barcelona")
                .with_deontic_modality(DeonticModality.FORBIDDEN)
                .with_from_time(year=2024, month=5)
                .build()
        )
        results = self.belief_service.search_by_subject_notion(
            self.subject_notion,
            modifier=ModifierBuilder()
                .with_location("Madrid")
                .with_deontic_modality(DeonticModality.FORBIDDEN)
                .with_from_time(year=2024, month=5)
                .build()
        )
        self.assertEqual(len(results), 1)
        self.assertEqual(results[0].location, "Madrid")
        self.assertEqual(results[0].deontic_modality, DeonticModality.FORBIDDEN)
        self.assertIsNotNone(results[0].from_time)
        self.assertEqual(results[0].from_time.year, 2024)
        self.assertEqual(results[0].from_time.month, 5)

    def test_belief_modifier_persists_after_adding_multiple_statements(self):
        modifier = Modifier(
            location="Rome",
            deontic_modality=DeonticModality.OBLIGATORY
        )
        self.statement_service.create(
            user_id=self.user.id,
            agent_id=self.agent.id,
            subject_notion=self.subject_notion,
            complement_notion=self.complement_notion,
            relation=Relation.from_string("is"),
            probability=0.8,
            validity=0.9,
            modifier=modifier
        )
        from analogai.foundation.modules.user.user import User
        other_user = User(id="other_user_id", name="Other User", email="other@example.com")
        self.statement_service.create(
            user_id=other_user.id,
            agent_id=self.agent.id,
            subject_notion=self.subject_notion,
            complement_notion=self.complement_notion,
            relation=Relation.from_string("is"),
            probability=0.7,
            validity=0.85,
            modifier=modifier
        )
        belief = self.belief_service.find(
            self.subject_notion, self.complement_notion, Relation.from_string("is"),
            modifier=modifier
        )
        self.assertIsNotNone(belief)
        self.assertEqual(len(belief.statements), 2)
        self.assertEqual(belief.location, "Rome")
        self.assertEqual(belief.deontic_modality, DeonticModality.OBLIGATORY)
        retrieved_belief = self.belief_service.find(
            self.subject_notion, self.complement_notion, Relation.from_string("is"),
            modifier=modifier
        )
        self.assertIsNotNone(retrieved_belief)
        if retrieved_belief is None:
            self.fail("Expected belief to be found")
        self.assertEqual(retrieved_belief.location, "Rome")
        self.assertEqual(retrieved_belief.deontic_modality, DeonticModality.OBLIGATORY)

    def test_search_beliefs_by_modifier_returns_empty_when_no_match(self):
        self.statement_service.create(
            user_id=self.user.id,
            agent_id=self.agent.id,
            subject_notion=self.subject_notion,
            complement_notion=self.complement_notion,
            relation=Relation.from_string("is"),
            probability=0.8,
            validity=0.9,
            modifier=Modifier(location="Amsterdam")
        )
        results = self.belief_service.search_by_subject_notion(
            self.subject_notion,
            modifier=Modifier(location="Brussels")
        )
        self.assertEqual(len(results), 0)

    def test_find_with_modifier_returns_matching_belief(self):
        modal_a = Modifier(location="Dublin")
        self.statement_service.create(
            user_id=self.user.id,
            agent_id=self.agent.id,
            subject_notion=self.subject_notion,
            complement_notion=self.complement_notion,
            relation=Relation.from_string("is"),
            probability=0.8,
            validity=0.9,
            modifier=modal_a
        )
        belief_by_modal = self.belief_service.find(
            self.subject_notion, self.complement_notion, Relation.from_string("is"), modifier=modal_a
        )
        self.assertIsNotNone(belief_by_modal)
        self.assertEqual(belief_by_modal.location, "Dublin")
        self.assertEqual(len(belief_by_modal.statements), 1)

    def test_find_with_modifier_returns_none_when_no_match(self):
        self.statement_service.create(
            user_id=self.user.id,
            agent_id=self.agent.id,
            subject_notion=self.subject_notion,
            complement_notion=self.complement_notion,
            relation=Relation.from_string("is"),
            probability=0.8,
            validity=0.9,
            modifier=Modifier(location="Cork")
        )
        other_modal = Modifier(location="Galway")
        belief = self.belief_service.find(
            self.subject_notion, self.complement_notion, Relation.from_string("is"), modifier=other_modal
        )
        self.assertIsNone(belief)

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