from analogai.foundation.common.enums import RelationshipType
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, Attribute
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


class StatementLearningInterpreter(Interpreter):
    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 (hasattr(relation, "is_of_type") and relation.is_of_type(RelationshipType.HAS_A)):
                return StatementType.SIMPLE

        subject_attrs = getattr(parsed_message.data.subject, "attributes", None)
        if parsed_message.data.attributes or subject_attrs:
            if relation is None or (
                hasattr(relation, "is_of_type") and relation.is_of_type(RelationshipType.HAS_A)
            ):
                return StatementType.NOTION_ATTRIBUTE
            for attr in parsed_message.data.attributes:
                if attr.values:
                    return StatementType.ATTRIBUTE_QUANTITY
            if subject_attrs and _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 = getattr(subject, "attributes", None)

        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:
            app_logger.info(
                "Statement dropped: missing complement for subject=%s relation=%s",
                getattr(subject, "caption", None),
                getattr(relation, "value", relation),
            )
            return None

        attributes = []
        if parsed_message.data.attributes:
            for attr in parsed_message.data.attributes:
                values = _coerce_float_values(attr.values)
                attributes.append(Attribute(
                    tag=attr.tag,
                    values=values,
                    unit=attr.unit,
                    min_value=attr.min_value,
                    max_value=attr.max_value,
                ))
        elif subject_attrs:
            for attribute in subject_attrs:
                values = _coerce_float_values([getattr(attribute, "value", None)])
                if not values and not getattr(attribute, "unit", None):
                    continue
                attributes.append(Attribute(
                    tag=attribute.tag,
                    values=values,
                    unit=attribute.unit,
                ))

        quantity = parsed_message.data.quantity

        if quantity is None and complement_expr:
            complement_caption_clean, quantity_from_caption = _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 = getattr(parsed_message.data, "certainty", None)
        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 _extract_quantity_from_caption(caption: str):
    if not caption:
        return caption, None
    tokens = caption.split()
    if not tokens or not tokens[0].isdigit():
        return caption, None
    try:
        q = float(tokens[0])
        rest = " ".join(tokens[1:]).strip()
        if rest and rest.endswith("s") and not rest.endswith("ss"):
            rest = rest[:-1]
        return rest, q
    except (ValueError, TypeError):
        return caption, None


def _coerce_float_values(values) -> list[float]:
    if not values:
        return []
    coerced: list[float] = []
    for value in values:
        try:
            coerced.append(float(value))
        except (TypeError, ValueError):
            continue
    return coerced


def _has_numeric_attribute_values(attributes) -> bool:
    if not attributes:
        return False
    for attribute in attributes:
        try:
            value = getattr(attribute, "value", None)
            if value is None:
                continue
            float(value)
            return True
        except (TypeError, ValueError):
            continue
    return False
