from analogai.deepthink.application.usecases.learning.make_direct_statement.models import MakeDirectStatementRequest, MakeDirectStatementResponse
from analogai.deepthink.application.usecases.learning.make_direct_statement.ports import LearnInputPort, MakeStatementOutputPort
from analogai.deepthink.application.usecases.learning.make_direct_statement.states.context.learner_context_handler import LearnerContextHandler
from analogai.deepthink.application.usecases.learning.make_direct_statement.states.common.response_builder import LearnerResponseBuilder
from analogai.deepthink.application.usecases.learning.make_direct_statement.states.find_statement_state import FindStatementState
from analogai.deepthink.application.usecases.learning.make_direct_statement.states.create_statement_state import CreateStatementState
from analogai.deepthink.application.usecases.learning.make_direct_statement.states.update_statement_state import UpdateStatementState
from analogai.deepthink.application.exceptions.authority_exceptions import InsufficientAuthorityError
from analogai.foundation.modules.notion.notion_service import NotionService
from analogai.foundation.common.design_patterns.state_machine import StateMachine
from analogai.foundation.common.logging.app_logger import app_logger


class MakeDirectStatementUseCase(LearnInputPort, StateMachine):
    def __init__(
        self,
        statement_service,
        notion_service: NotionService,
        output_port: MakeStatementOutputPort,
        context_handler: LearnerContextHandler,
        response_builder: LearnerResponseBuilder,
    ):
        StateMachine.__init__(self, context_handler.context)
        self._statement_service = statement_service
        self._notion_service = notion_service
        self._output_port = output_port
        self._context_handler = context_handler
        self._response_builder = response_builder

        self.find_statement_state = FindStatementState(self, statement_service)
        self.update_statement_state = UpdateStatementState(self, statement_service, output_port, response_builder)
        self.create_statement_state = CreateStatementState(
            self,
            statement_service,
            notion_service,
            output_port,
            response_builder,
        )

    def execute(self, request: MakeDirectStatementRequest, output_port_override=None):
        app_logger.info(f"Learning statement: {repr(request)}")

        context_handler, response_builder = self._create_execution_context(request)
        
        previous_output_ports = self._configure_output_ports(output_port_override, response_builder)

        try:
            result = self._process_learning_request(request, context_handler, response_builder)
            app_logger.info(f"Successfully processed learning statement: {repr(request)}")
            return result
        except InsufficientAuthorityError:
            return self._handle_insufficient_authority(request, response_builder)
        finally:
            self._restore_output_ports(previous_output_ports)

    def _create_execution_context(self, request: MakeDirectStatementRequest):
        from analogai.deepthink.application.usecases.learning.make_direct_statement.states.context.learner_context import LearnerContext
        from analogai.deepthink.application.usecases.learning.make_direct_statement.states.context.learner_context_handler import LearnerContextHandler
        from analogai.deepthink.application.usecases.learning.make_direct_statement.states.common.response_builder import LearnerResponseBuilder

        context = LearnerContext()
        context_handler = LearnerContextHandler(context, self._notion_service)
        response_builder = LearnerResponseBuilder(context)
        
        return context_handler, response_builder
    
    def _configure_output_ports(self, output_port_override, response_builder):
        port = output_port_override if output_port_override else self._output_port
        
        previous_ports = {
            'update': self.update_statement_state._output_port,
            'create': self.create_statement_state._output_port
        }
        
        self.update_statement_state._output_port = port
        self.create_statement_state._output_port = port
        self.update_statement_state._response_builder = response_builder
        self.create_statement_state._response_builder = response_builder
        
        return previous_ports
    
    def _restore_output_ports(self, previous_ports):
        self.update_statement_state._output_port = previous_ports['update']
        self.create_statement_state._output_port = previous_ports['create']
    
    def _process_learning_request(self, request, context_handler, response_builder):
        context_handler.create_from_request(request)
        self.set_context(context_handler.context)
        return self._execute_state_machine()
    
    def _handle_insufficient_authority(self, request, response_builder):
        try:
            response = response_builder.build_response()
            return self._output_port.output_forbidden(response)
        except Exception:
            fallback_response = self._create_fallback_response(request)
            return self._output_port.output_forbidden(fallback_response)
    
    def _create_fallback_response(self, request):
        from analogai.foundation.common.dtos.belief_expression import BeliefExpression
        
        belief_expression = BeliefExpression(
            subject_notion_expression=request.subject_notion_expression,
            complement_notion_expression=request.complement_notion_expression,
            relation=request.relation,
            probability=request.probability,
            validity=1.0,
            modifier=request.modifier
        )
        
        return MakeDirectStatementResponse(
            user_agent=request.user_agent,
            belief_expression=belief_expression
        )

    def _execute_state_machine(self):
        if not self.context:
            raise ValueError("context should be set")
        return self.state_to_find_statement()

    def state_to_find_statement(self):
        return self.state_to(self.find_statement_state)

    def state_to_update_statement(self):
        return self.state_to(self.update_statement_state)

    def state_to_create_statement(self):
        return self.state_to(self.create_statement_state)
