from analogai.deepthink.application.utils.certainty.certainty_comparison_util import check_update_statement_applicable
from analogai.deepthink.application.usecases.learning.make_direct_statement.ports import MakeStatementOutputPort
from analogai.foundation.common.design_patterns.state_machine import State
from analogai.foundation.common.logging.app_logger import app_logger
from analogai.deepthink.application.usecases.learning.make_direct_statement.utils.modifier_util import modifiers_match
from .common.response_builder import LearnerResponseBuilder


class UpdateStatementState(State):
    def __init__(self, state_machine, statement_service, output_port: MakeStatementOutputPort,
                 response_builder: LearnerResponseBuilder):
        super().__init__(state_machine)
        self._statement_service = statement_service
        self._response_builder = response_builder
        self._output_port = output_port

    def execute(self):
        if self.context.statement is None:
            app_logger.warning(
                "Skipping update check because no existing statement is present."
            )
            return self._build_and_output_not_applicable_response()

        app_logger.info(
            "Checking if statement update is applicable: "
            f"existing probability={self.context.statement.probability}, "
            f"proposed={self.context.proposed_probability}"
        )
        
        if not self._validate_modifier_matches():
            app_logger.info("Modifiers don't match, update not applicable")
            return self._build_and_output_not_applicable_response()
        
        if self._check_is_statement_already_known():
            app_logger.info("Statement already known with same probability")
            return self._build_and_output_statement_already_known()
        
        if self._check_should_update_statement():
            app_logger.info("Updating statement probability and validity")
            return self._apply_update_and_output_success()
        
        app_logger.info("Update not applicable based on certainty comparison")
        return self._build_and_output_not_applicable_response()

    def _check_should_update_statement(self):
        if self.context.statement is None:
            return False
        return check_update_statement_applicable(
            self.context.statement.probability,
            self.context.proposed_probability,
            self.context.statement.validity,
            self.context.proposed_validity
        )

    def _check_is_statement_already_known(self):
        if self.context.statement is None:
            return False
        return self.context.statement.probability == self.context.proposed_probability

    def _apply_update_and_output_success(self):
        if self.context.statement:
            updated_statement = self._statement_service.update_probability(
                self.context.statement,
                self.context.proposed_probability
            )
            updated_statement = self._statement_service.update_validity(
                updated_statement,
                self.context.proposed_validity
            )
            self.context.statement = updated_statement
        response = self._response_builder.build_response()
        return self._output_port.output_statement_update_success(response)

    def _build_and_output_statement_already_known(self):
        response = self._response_builder.build_response()
        return self._output_port.output_statement_already_known(response)

    def _build_and_output_not_applicable_response(self):
        response = self._response_builder.build_response()
        return self._output_port.output_update_not_applicable(response)

    def _validate_modifier_matches(self) -> bool:
        statement_modal = self.context.statement.modifier if self.context.statement else None
        request_modal = self.context.modifier
        return modifiers_match(statement_modal, request_modal)

