from analogai.deepthink.startup.factories.domain_service_factory import DomainServiceFactory
from analogai.deepthink.presentation.parsers.text_manipulation.formatting_strategies import format_location
from analogai.foundation.common.enums import RelationshipType
from analogai.foundation.core.value_objects.cause import Cause
from analogai.foundation.common.enums.criterion import Criterion
from analogai.foundation.common.dtos.belief_expression import BeliefExpression
from analogai.foundation.common.dtos.notion_expression import NotionExpression
from analogai.foundation.core.value_objects.relation import Relation
from analogai.deepthink.application.usecases.learning.make_hypothetical_statement.models import (
    CauseCriteria,
    MakeHypotheticalStatementRequest,
    MakeHypotheticalStatementResponse,
    CriterionData,
)
from analogai.deepthink.application.usecases.learning.make_hypothetical_statement.ports import (
    MakeHypotheticalStatementOutputPort,
)
from analogai.deepthink.application.exceptions.authority_exceptions import InsufficientAuthorityError
from analogai.foundation.common.logging.app_logger import app_logger

_CRITERION_BY_VALUE = {c.value: c for c in Criterion}


def _normalize_for_comparison(value: str) -> str:
    if value is None:
        return ""
    return str(value).strip().lower()


class MakeHypotheticalStatementUseCase:
    def __init__(
        self,
        domain_service_factory: DomainServiceFactory,
        output_port: MakeHypotheticalStatementOutputPort,
    ):
        self._domain_service_factory = domain_service_factory
        self._output_port = output_port

    def execute(self, request: MakeHypotheticalStatementRequest):
        if request.user_agent.user_authority == 0.0:
            raise InsufficientAuthorityError(
                f"User {request.user_agent.user_id} attempted to make a hypothetical statement with 0 authority"
            )
        first_cause = request.causes[0]
        subject_caption = self._display_caption(first_cause.criteria, for_effect=False)
        complement_caption = self._display_caption(request.effect.criteria, for_effect=True)

        app_logger.info(
            "Processing hypothetical statement: '%s' -> '%s'",
            subject_caption,
            complement_caption,
        )
        app_logger.info(
            "Cause criteria: %s",
            first_cause.criteria,
        )
        app_logger.info(
            "Effect criteria: %s",
            request.effect.criteria,
        )

        if _normalize_for_comparison(subject_caption) == _normalize_for_comparison(complement_caption):
            app_logger.info("Forbidden: cause and effect are identical")
            response = self._build_response(request)
            return self._output_port.output_forbidden(response)

        hypothetical_statement_service = self._domain_service_factory.get_hypothetical_statement_service()
        cause_dicts = [self._to_criterion_dict(c.criteria) for c in request.causes]
        effect_dict = self._to_criterion_dict(request.effect.criteria)

        app_logger.info(
            "Converted to criterion dicts - causes: %s, effect: %s",
            cause_dicts,
            effect_dict,
        )

        try:
            hypothetical_statement_service.create(
                user_id=request.user_agent.user_id,
                agent_id=request.user_agent.agent_id,
                causes=[Cause(cd) for cd in cause_dicts],
                effect=Cause(effect_dict),
            )
            app_logger.info("Hypothetical statement service create succeeded")
        except (ValueError, AttributeError) as e:
            app_logger.error("Hypothetical statement service create failed: %s", e)
            response = self._build_response(request)
            return self._output_port.output_forbidden(response)
        subject_expr = NotionExpression(caption=subject_caption)
        complement_expr = NotionExpression(caption=complement_caption)
        belief_expression = BeliefExpression(
            subject_notion_expression=subject_expr,
            complement_notion_expression=complement_expr,
            relation=Relation.from_string("causes"),
            probability=1.0,
            validity=1.0,
            modifier=None,
        )
        response = MakeHypotheticalStatementResponse(
            user_agent=request.user_agent,
            belief_expression=belief_expression,
            causes=request.causes,
            effect=request.effect,
            validity=1.0,
            effect_belief_id=None,
        )
        return self._output_port.output_create_statement_success(response)

    def _display_caption(self, criteria: CriterionData, for_effect: bool = False) -> str:
        location = criteria.location
        if location and criteria.subject_caption == "it":
            caption = (
                criteria.complement_caption
                or ""
            )
            return format_location(caption, location) if caption else ""
        if for_effect:
            caption = criteria.complement_caption or ""
        else:
            caption = criteria.subject_caption or ""
        if isinstance(caption, str) and location:
            return format_location(caption, location)
        return str(caption)

    def _to_criterion_dict(self, criteria: CriterionData):
        result = {}
        if criteria.complement_caption is not None:
            result[Criterion.ComplementCaption] = criteria.complement_caption
        if criteria.subject_caption is not None:
            result[Criterion.SubjectCaption] = criteria.subject_caption
        if criteria.relation is not None:
            relation_value = criteria.relation
            if isinstance(relation_value, str):
                relation_value = Relation.from_string(relation_value)
            result[Criterion.Relation] = relation_value
        if criteria.location is not None:
            result[Criterion.Location] = criteria.location
        if criteria.time is not None:
            result[Criterion.Time] = criteria.time
        if criteria.from_time is not None:
            result[Criterion.FromTime] = criteria.from_time
        if criteria.to_time is not None:
            result[Criterion.ToTime] = criteria.to_time
        if criteria.quantity is not None:
            result[Criterion.Quantity] = criteria.quantity
        if criteria.deontic_modality is not None:
            result[Criterion.DeonticModality] = criteria.deontic_modality
        if criteria.certainty is not None:
            result[Criterion.Certainty] = criteria.certainty
        if criteria.attribute_values:
            result[Criterion.AttributeValue] = [
                {
                    "tag": value.tag,
                    "value": value.value,
                    "unit": value.unit,
                    "min_value": value.min_value,
                    "max_value": value.max_value,
                }
                for value in criteria.attribute_values
            ]
        return result

    def _build_response(self, request: MakeHypotheticalStatementRequest):
        first_cause = request.causes[0]
        subject_expr = NotionExpression(caption=self._display_caption(first_cause.criteria))
        complement_expr = NotionExpression(caption=self._display_caption(request.effect.criteria, for_effect=True))
        belief_expression = BeliefExpression(
            subject_notion_expression=subject_expr,
            complement_notion_expression=complement_expr,
            relation=Relation.from_string("causes"),
            probability=1.0,
            validity=1.0,
            modifier=None,
        )
        return MakeHypotheticalStatementResponse(
            user_agent=request.user_agent,
            belief_expression=belief_expression,
            causes=request.causes,
            effect=request.effect,
            validity=1.0,
            effect_belief_id=None,
        )
