from unittest import TestCase

from analogai.foundation.settings import config
from analogai.foundation.modules.notion.notion import Notion
from analogai.foundation.core.value_objects.relation import Relation
from analogai.foundation.modules.fact.factories.fact_factory import FactServiceFactory
from analogai.foundation.modules.fact.source.fact_source import UrlSource
from analogai.foundation.modules.fact.source.repositories.infrastructure.in_memory_fact_source_repository import (
    InMemoryFactSourceRepository,
)
from analogai.foundation.modules.fact.repositories.infrastructure.in_memory_fact_repository import (
    InMemoryFactRepository,
)
from analogai.foundation.modules.fact.source.services.fact_source_service import FactSourceService
from analogai.foundation.tests.functional.services.setup import ServicesTestConfig


class TestFactSourceServiceFunctional(TestCase):
    def setUp(self):
        self._config_override = config.override(
            **{"vector_search.enabled": False, "ENVIRONMENT": "development"}
        )
        self._config_override.__enter__()
        self.config = ServicesTestConfig()

        self.source_repo = InMemoryFactSourceRepository()
        self.fact_service = FactServiceFactory(
            repository=InMemoryFactRepository(),
            source_repository=self.source_repo,
            statement_service=self.config.statement_service,
            notion_service=self.config.notion_service,
        ).create()
        self.fact_source_service = FactSourceService(
            fact_service=self.fact_service,
            belief_service=self.config.belief_service,
            source_repository=self.source_repo,
        )

        self.subject_notion = Notion(
            user_id=self.config.user.id,
            agent_id=self.config.agent.id,
            caption="human",
            id="human_id",
        )
        self.complement_notion = Notion(
            user_id=self.config.user.id,
            agent_id=self.config.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()
        if self._config_override:
            self._config_override.__exit__(None, None, None)

    def test_delete_source_removes_facts_and_statements(self):
        source = UrlSource("https://example.com", agent_id=self.config.agent.id)
        statement = self.config.statement_service.create(
            user_id=self.config.user.id,
            agent_id=self.config.agent.id,
            subject_notion=self.subject_notion,
            complement_notion=self.complement_notion,
            relation=Relation.from_string("is"),
            probability=0.9,
            validity=0.9,
        )
        self.fact_service.record_direct_statement_fact(
            user_id=self.config.user.id,
            agent_id=self.config.agent.id,
            statement_id=statement.id,
            text="Humans are mortal.",
            role="user",
            source=source,
        )
        self.fact_service.record_notion_fact(
            user_id=self.config.user.id,
            agent_id=self.config.agent.id,
            notion_id=self.subject_notion.id,
            text="Humans are mortal.",
            role="user",
            source=source,
        )
        belief = self.config.belief_service.find(
            self.subject_notion,
            self.complement_notion,
            Relation.from_string("is"),
        )
        self.assertIsNotNone(belief)
        if belief is None:
            self.fail("Expected belief to be created")

        result = self.fact_source_service.delete_source(source.id)

        self.assertTrue(result["fact_ids"], "Expected fact ids to be returned")
        self.assertEqual(result["belief_ids"], [belief.id])
        self.assertIsNone(self.source_repo.get_source(source.id))
        self.assertIsNone(
            self.config.statement_service.find_by_id(statement.id),
            "Expected fact deletion to remove statement",
        )
        self.assertIsNone(
            self.config.notion_service.find_by_id(self.subject_notion.id),
            "Expected fact deletion to remove notion",
        )

    def test_get_sources_returns_registered_sources(self):
        source = UrlSource("https://example.com/facts", agent_id=self.config.agent.id)
        statement = self.config.statement_service.create(
            user_id=self.config.user.id,
            agent_id=self.config.agent.id,
            subject_notion=self.subject_notion,
            complement_notion=self.complement_notion,
            relation=Relation.from_string("is"),
            probability=0.9,
            validity=0.9,
        )
        self.fact_service.record_direct_statement_fact(
            user_id=self.config.user.id,
            agent_id=self.config.agent.id,
            statement_id=statement.id,
            text="Facts can have sources.",
            role="user",
            source=source,
        )

        sources = self.fact_source_service.get_sources(self.config.agent.id)

        self.assertTrue(sources, "Expected sources to be returned")
        self.assertIn(source.id, {item.id for item in sources})

    def test_store_and_get_source_round_trip(self):
        source = UrlSource("https://example.com/store", agent_id=self.config.agent.id)
        stored = self.fact_source_service.store_source(source)

        self.assertIsNotNone(stored)
        self.assertEqual(stored.id, source.id)
        fetched = self.fact_source_service.get_source(source.id)

        self.assertIsNotNone(fetched)
        if fetched is None:
            self.fail("Expected stored source to be retrievable")
        self.assertEqual(fetched.id, source.id)
