import unittest
from datetime import datetime
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.common.enums.deontic_modality import DeonticModality
from analogai.foundation.tests.functional.services.setup import ServicesTestConfig


class TestStatementServiceFunctional(unittest.TestCase):
    def setUp(self):
        self.config = ServicesTestConfig()
        self.statement_service = self.config.statement_service
        self.user = self.config.user
        self.agent = self.config.agent
        self.subject_notion = Notion(
            user_id=self.user.id,
            agent_id=self.agent.id,
            caption="socrates",
            id="socrates_id",
        )
        self.relation = Relation.from_string("sell")
        self.complement_notion = Notion(
            user_id=self.user.id,
            agent_id=self.agent.id,
            caption="iphone",
            id="iphone_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_create_statement_with_quantity_socrates_sell_2_iphones(self):
        created = self.statement_service.create(
            user_id=self.user.id,
            agent_id=self.agent.id,
            subject_notion=self.subject_notion,
            relation=self.relation,
            complement_notion=self.complement_notion,
            quantity=2.0,
        )
        self.assertIsNotNone(created.id)
        self.assertEqual(created.quantity, 2.0)
        self.assertEqual(created.subject_notion.caption, "socrates")
        self.assertEqual(created.relation, Relation.from_string("sell"))
        self.assertEqual(created.complement_notion.caption, "iphone")

        found = self.statement_service.find_by_id(created.id)
        self.assertIsNotNone(found)
        self.assertEqual(found.quantity, 2.0)
        self.assertIsNotNone(found.created_at)
        self.assertIsInstance(found.created_at, datetime)

    def test_statement_created_at_persists(self):
        created = self.statement_service.create(
            user_id=self.user.id,
            agent_id=self.agent.id,
            subject_notion=self.subject_notion,
            relation=self.relation,
            complement_notion=self.complement_notion,
        )
        self.assertIsNotNone(created.created_at)
        original_created_at = created.created_at

        found = self.statement_service.find_by_id(created.id)
        self.assertIsNotNone(found)
        self.assertIsNotNone(found.created_at)
        self.assertEqual(found.created_at.isoformat(), original_created_at.isoformat())

    def test_statement_modifier_persists_location_deontic_and_times(self):
        modifier = ModifierBuilder().with_location("Paris").with_deontic_modality(
            DeonticModality.OBLIGATORY
        ).with_from_time(year=2024, month=3, day=15, hour=10, minute=30).with_to_time(
            year=2024, month=6, day=20
        ).build()
        created = self.statement_service.create(
            user_id=self.user.id,
            agent_id=self.agent.id,
            subject_notion=self.subject_notion,
            relation=self.relation,
            complement_notion=self.complement_notion,
            modifier=modifier,
        )
        self.assertIsNotNone(created.id)
        self.assertIsNotNone(created.modifier)
        self.assertEqual(created.modifier.location, "Paris")
        self.assertEqual(created.modifier.deontic_modality, DeonticModality.OBLIGATORY)
        self.assertEqual(created.modifier.from_time.year, 2024)
        self.assertEqual(created.modifier.from_time.month, 3)
        self.assertEqual(created.modifier.from_time.day, 15)
        self.assertEqual(created.modifier.from_time.hour, 10)
        self.assertEqual(created.modifier.from_time.minute, 30)
        self.assertEqual(created.modifier.to_time.year, 2024)
        self.assertEqual(created.modifier.to_time.month, 6)
        self.assertEqual(created.modifier.to_time.day, 20)

        found = self.statement_service.find_by_id(created.id)
        self.assertIsNotNone(found)
        self.assertIsNotNone(found.modifier)
        self.assertEqual(found.modifier.location, "Paris")
        self.assertEqual(found.modifier.deontic_modality, DeonticModality.OBLIGATORY)
        self.assertEqual(found.modifier.from_time.year, 2024)
        self.assertEqual(found.modifier.from_time.month, 3)
        self.assertEqual(found.modifier.from_time.day, 15)
        self.assertEqual(found.modifier.from_time.hour, 10)
        self.assertEqual(found.modifier.from_time.minute, 30)
        self.assertEqual(found.modifier.to_time.year, 2024)
        self.assertEqual(found.modifier.to_time.month, 6)
        self.assertEqual(found.modifier.to_time.day, 20)

    def test_statement_find_by_subject_and_relation_filters_by_modifier(self):
        modifier_paris = Modifier(location="Paris", deontic_modality=DeonticModality.OBLIGATORY)
        modifier_london = Modifier(location="London", deontic_modality=DeonticModality.PERMITTED)
        self.statement_service.create(
            user_id=self.user.id,
            agent_id=self.agent.id,
            subject_notion=self.subject_notion,
            relation=self.relation,
            complement_notion=self.complement_notion,
            modifier=modifier_paris,
        )
        self.statement_service.create(
            user_id=self.user.id,
            agent_id=self.agent.id,
            subject_notion=self.subject_notion,
            relation=self.relation,
            complement_notion=self.complement_notion,
            modifier=modifier_london,
        )

        results_paris = self.statement_service.find_by_subject_and_relation(
            self.subject_notion, Relation.from_string("sell"), modifier=Modifier(location="Paris")
        )
        results_london = self.statement_service.find_by_subject_and_relation(
            self.subject_notion, Relation.from_string("sell"), modifier=Modifier(location="London")
        )
        self.assertEqual(len(results_paris), 1)
        self.assertEqual(len(results_london), 1)
        self.assertEqual(results_paris[0].modifier.location, "Paris")
        self.assertEqual(results_london[0].modifier.location, "London")

    def test_statement_find_by_object_and_relation_filters_by_modifier(self):
        modifier = Modifier(location="Tokyo", deontic_modality=DeonticModality.FORBIDDEN)
        self.statement_service.create(
            user_id=self.user.id,
            agent_id=self.agent.id,
            subject_notion=self.subject_notion,
            relation=self.relation,
            complement_notion=self.complement_notion,
            modifier=modifier,
        )

        results = self.statement_service.find_by_object_and_relation(
            self.complement_notion, Relation.from_string("sell"), modifier=Modifier(location="Tokyo")
        )
        self.assertEqual(len(results), 1)
        self.assertEqual(results[0].modifier.location, "Tokyo")
        self.assertEqual(results[0].modifier.deontic_modality, DeonticModality.FORBIDDEN)


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