from analogai.foundation.common.enums import RelationshipType
from analogai.foundation.core.value_objects.relation import Relation
from analogai.foundation.common.enums.certainty import Certainty
from analogai.foundation.common.logging.app_logger import app_logger
from analogai.foundation.common.utils.expression_factory import ExpressionFactory

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.interpreter import Interpreter
from analogai.deepthink.presentation.interpreters.interpreter_result import InterpreterResult
from analogai.deepthink.presentation.interpreters.utils.modifier_builder import build_modifier_from_parsed
from analogai.deepthink.presentation.interpreters.utils.statement_attribute_helper import (
    StatementAttributeHelper,
)


class StatementLearningInterpreter(Interpreter):
    def __init__(self):
        self._attribute_helper = StatementAttributeHelper()

    def interpret(self, parsed_message, user_agent, message_text):
        if parsed_message is None:
            return None
        if parsed_message.intent_type != IntentType.MAKING_STATEMENT:
            return None
        modifier = build_modifier_from_parsed(parsed_message.data, user_agent)
        statement_type = self._resolve_statement_type(parsed_message)
        request = self._build_request(parsed_message, user_agent, modifier, statement_type)
        if request is None:
            return None
        subject_caption = parsed_message.data.subject.caption if parsed_message.data.subject else ""
        app_logger.info(
            "Statement interpreted: type=%s subject=%s",
            statement_type.value,
            subject_caption,
        )
        return InterpreterResult(intent_type=IntentType.MAKING_STATEMENT, request=request)

    def _resolve_statement_type(self, parsed_message):
        relation = parsed_message.data.relation
        if relation and parsed_message.data.complement is not None:
            if not _relation_is_has_a(relation):
                return StatementType.SIMPLE

        subject_attrs = self._attribute_helper.get_subject_attributes(parsed_message.data.subject)
        if parsed_message.data.attributes or subject_attrs:
            if relation is None or _relation_is_has_a(relation):
                return StatementType.NOTION_ATTRIBUTE
            for attr in parsed_message.data.attributes:
                if attr.values:
                    return StatementType.ATTRIBUTE_QUANTITY
            if subject_attrs and self._attribute_helper.has_numeric_attribute_values(subject_attrs):
                return StatementType.ATTRIBUTE_QUANTITY
        return StatementType.SIMPLE

    def _build_request(self, parsed_message, user_agent, modifier, statement_type):
        subject = parsed_message.data.subject
        if not subject:
            return None
        subject_attrs = self._attribute_helper.get_subject_attributes(subject)

        expression_factory = ExpressionFactory()
        complement_expr = parsed_message.data.complement
        relation = parsed_message.data.relation

        probability = self._resolve_probability(parsed_message)

        if statement_type == StatementType.NOTION_ATTRIBUTE:
            return LearnStatementRequest(
                user_agent=user_agent,
                statement_type=statement_type,
                subject=subject,
                complement=None,
                relation=relation,
                probability=probability,
                modifier=modifier,
                attributes=[],
                quantity=None,
                from_time=parsed_message.data.from_time,
                to_time=parsed_message.data.to_time,
                location=parsed_message.data.location,
                deontic_modality=parsed_message.data.deontic_modality,
            )

        if complement_expr is None:
            relation_text = _relation_value(relation)
            if relation_text:
                from analogai.foundation.common.utils.lemmatization.lemmatizer import lemmatize_text

                normalized = lemmatize_text(relation_text, preserve_proper=False)
                if not normalized:
                    normalized = relation_text
                if normalized == relation_text and normalized.endswith("s") and len(normalized) > 1:
                    normalized = normalized[:-1]
                complement_expr = expression_factory.create_notion_expression(normalized)
                relation = Relation.from_type(RelationshipType.DO)
            else:
                app_logger.info(
                    "Statement dropped: missing complement for subject=%s relation=%s",
                    _notion_caption(subject),
                    _relation_value(relation),
                )
                return None

        attributes = self._attribute_helper.build_attributes(
            parsed_message.data.attributes,
            subject_attrs,
        )

        quantity = parsed_message.data.quantity

        if quantity is None and complement_expr:
            complement_caption_clean, quantity_from_caption = self._attribute_helper.extract_quantity_from_caption(
                complement_expr.caption
            )
            if quantity_from_caption is not None:
                quantity = quantity_from_caption
                complement_expr = expression_factory.create_notion_expression(complement_caption_clean)

        return LearnStatementRequest(
            user_agent=user_agent,
            statement_type=statement_type,
            subject=subject,
            complement=complement_expr,
            relation=relation,
            probability=probability,
            modifier=modifier,
            attributes=attributes,
            quantity=quantity,
            from_time=parsed_message.data.from_time,
            to_time=parsed_message.data.to_time,
            location=parsed_message.data.location,
            deontic_modality=parsed_message.data.deontic_modality,
        )

    def _resolve_probability(self, parsed_message) -> float:
        certainty = _parsed_certainty(parsed_message.data)
        probability = parsed_message.data.probability
        if certainty == Certainty.NEGATED:
            return 0.0
        if certainty == Certainty.UNCERTAIN and probability is None:
            return 0.5
        return probability if probability is not None else 1.0


def _relation_is_has_a(relation) -> bool:
    if relation is None:
        return False
    try:
        return relation.is_of_type(RelationshipType.HAS_A)
    except AttributeError:
        return False


def _notion_caption(notion) -> str | None:
    if notion is None:
        return None
    try:
        return notion.caption
    except AttributeError:
        return None


def _relation_value(relation) -> str:
    if relation is None:
        return ""
    try:
        return relation.value
    except AttributeError:
        return str(relation)


def _parsed_certainty(parsed_data) -> Certainty | None:
    if parsed_data is None:
        return None
    try:
        return parsed_data.certainty
    except AttributeError:
        return None


