import unittest

from analogai.foundation.common.enums import RelationshipType
from analogai.foundation.common.enums.deontic_modality import DeonticModality
from analogai.foundation.core.value_objects.relation import Relation
from analogai.deepthink.application.value_objects.user_agent import UserAgent
from analogai.deepthink.application.usecases.learning.learn_statement.models import LearnStatementRequest, StatementType
from analogai.deepthink.presentation.intent_type import IntentType
from analogai.deepthink.presentation.interpreters.collection.statement_learning_interpreter import StatementLearningInterpreter
from analogai.deepthink.presentation.parsers.parsers_factory import build_message_parser


def _parse_and_interpret(json_text: str, user_agent: UserAgent):
    parser = build_message_parser()
    parsed_list = parser.parse(json_text)
    if not parsed_list:
        return None
    interpreter = StatementLearningInterpreter()
    return interpreter.interpret(parsed_list[0], user_agent, json_text)


class TestMakeStatementInterpreter(unittest.TestCase):
    def setUp(self):
        self.user_agent = UserAgent(user_id="u", agent_id="a", user_authority=1.0)

    def test_parses_structured_statement_formats(self):
        test_cases = [
            ('{"intent":"making_statement","subject":"socrates","relationship":"is_a","object":"human","probability":1.0}', StatementType.SIMPLE, Relation.from_type(RelationshipType.IS_A), 1.0),
            ('{"intent":"making_statement","subject":"socrates","relationship":"is_a","object":"mortal","probability":0.5}', StatementType.SIMPLE, Relation.from_type(RelationshipType.IS_A), 0.5),
            ('{"intent":"making_statement","subject":"socrates","relationship":"is_a","object":"god","probability":0.0}', StatementType.SIMPLE, Relation.from_type(RelationshipType.IS_A), 0.0),
        ]
        for json_text, expected_statement_type, expected_relationship_type, expected_probability in test_cases:
            with self.subTest(message=json_text):
                result = _parse_and_interpret(json_text, self.user_agent)
                self.assertIsNotNone(result, f"Failed for: {json_text}")
                self.assertIsInstance(result.request, LearnStatementRequest)
                self.assertEqual(result.request.statement_type, expected_statement_type)
                self.assertIsNotNone(result.request.subject)
                self.assertIsNotNone(result.request.complement)
                self.assertIsNotNone(result.request.relation)
                self.assertEqual(result.request.relation, expected_relationship_type)
                self.assertEqual(result.request.probability, expected_probability)
                self.assertEqual(result.intent_type, IntentType.MAKING_STATEMENT)

    def test_statement_only_creates_do_object_pattern(self):
        json_text = '{"intent":"making_statement","subject":"stock market","relationship":"works","probability":1.0}'
        result = _parse_and_interpret(json_text, self.user_agent)
        self.assertIsNotNone(result)
        self.assertIsInstance(result.request, LearnStatementRequest)
        self.assertEqual(result.request.statement_type, StatementType.SIMPLE)
        self.assertEqual(result.request.relation, Relation.from_type(RelationshipType.DO))
        self.assertEqual(result.request.complement.caption, "work")
        self.assertEqual(result.request.subject.caption, "stock market")

    def test_existential_normalized_to_present_object(self):
        json_text = '{"intent":"making_statement","subject":"winter","object":"present","relationship":"is","probability":1.0}'
        result = _parse_and_interpret(json_text, self.user_agent)
        self.assertIsNotNone(result)
        self.assertIsInstance(result.request, LearnStatementRequest)
        self.assertEqual(result.request.statement_type, StatementType.SIMPLE)
        self.assertEqual(result.request.relation, Relation.from_type(RelationshipType.IS_A))
        self.assertEqual(result.request.subject.caption, "winter")
        self.assertEqual(result.request.complement.caption, "present")

    def test_handles_statements_without_modifier(self):
        json_text = '{"intent":"making_statement","subject":"socrates","relationship":"is_a","object":"human","probability":1.0}'
        result = _parse_and_interpret(json_text, self.user_agent)
        self.assertIsNotNone(result)
        self.assertIsInstance(result.request, LearnStatementRequest)
        self.assertEqual(result.request.statement_type, StatementType.SIMPLE)
        self.assertIsNone(result.request.modifier)

    def test_time_prefix_populates_modifier_from_time(self):
        time_cases = [
            '{"intent":"making_statement","time":"today","subject":"it","relationship":"has_property","object":"rain","probability":1.0}',
            '{"intent":"making_statement","time":"tomorrow","subject":"it","relationship":"has_property","object":"rain","probability":1.0}',
            '{"intent":"making_statement","time":"yesterday","subject":"it","relationship":"has_property","object":"rain","probability":1.0}',
            '{"intent":"making_statement","deontic":"permitted","time":"today","subject":"you","relationship":"sell","object":"iphone 12","probability":1.0}',
        ]
        for json_text in time_cases:
            with self.subTest(message=json_text):
                result = _parse_and_interpret(json_text, self.user_agent)
                self.assertIsNotNone(result, f"Failed for: {json_text}")
                self.assertIsInstance(result.request, LearnStatementRequest)
                self.assertEqual(result.request.statement_type, StatementType.SIMPLE)
                req = result.request
                self.assertIsNotNone(req.modifier, f"modifier must be set when time is present: {json_text}")
                self.assertIsNotNone(req.modifier.from_time, f"from_time must be saved in modifier when time is present: {json_text}")

    def test_handles_statements_with_modifier(self):
        test_cases = [
            ('{"intent":"making_statement","location":"Tbilisi","subject":"it","relationship":"has_property","object":"rain","probability":1.0}', "Tbilisi", None, None, None),
            ('{"intent":"making_statement","time":"today","subject":"it","relationship":"has_property","object":"rain","probability":1.0}', None, "today", None, None),
            ('{"intent":"making_statement","deontic":"obligatory","subject":"you","relationship":"read","object":"books","probability":1.0}', None, None, None, "obligatory"),
            ('{"intent":"making_statement","deontic":"permitted","time":"today","subject":"you","relationship":"sell","object":"iphone 12","probability":1.0}', None, "today", None, "permitted"),
        ]
        for json_text, expected_location, expected_time, expected_to_time, expected_deontic in test_cases:
            with self.subTest(message=json_text):
                result = _parse_and_interpret(json_text, self.user_agent)
                self.assertIsNotNone(result, f"Failed for: {json_text}")
                self.assertIsInstance(result.request, LearnStatementRequest)
                self.assertEqual(result.request.statement_type, StatementType.SIMPLE)
                req = result.request
                self.assertEqual(result.intent_type, IntentType.MAKING_STATEMENT)
                if expected_location:
                    self.assertIsNotNone(req.modifier)
                    self.assertEqual(req.modifier.location, expected_location)
                if expected_time:
                    self.assertIsNotNone(req.modifier, f"modifier required for time: {json_text}")
                    self.assertIsNotNone(req.modifier.from_time, f"from_time must be saved in modifier: {json_text}")
                if expected_deontic:
                    self.assertIsNotNone(req.modifier)
                    self.assertEqual(req.modifier.deontic_modality, DeonticModality(expected_deontic))


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