from analogai.foundation.modules.notion.notion_service import NotionService
from analogai.foundation.common.design_patterns.state_machine import State
from analogai.foundation.common.dtos.notion_expression import NotionExpression
from analogai.foundation.common.enums import RelationshipType
from analogai.foundation.core.value_objects import Relation
from analogai.foundation.common.logging.app_logger import app_logger
from analogai.deepthink.application.utils.relationship_phrase_util import is_semantic_relationship
from .common.response_builder import LearnerResponseBuilder
from analogai.deepthink.application.usecases.learning.make_direct_statement.ports import MakeStatementOutputPort


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

    def execute(self):
        app_logger.info(f"Creating new statement: subject={repr(self.context.subject_notion)}, complement={repr(self.context.complement_notion)}, relation={self.context.relation}")
        
        if self._is_subject_object_same():
            app_logger.info("Forbidden: subject and object are the same")
            return self._output_forbidden_response()

        if not is_semantic_relationship(self.context.relation):
            app_logger.info("Non-semantic relationship, creating simple statement")
            return self._create_statement_and_output()

        app_logger.info("Semantic relationship, generating statement hierarchy")
        main_statement = self._generate_statement_hierarchy()
        if main_statement is None:
            app_logger.info("Forbidden: statement hierarchy generation failed")
            return self._output_forbidden_response()

        self._store_statement_in_context(main_statement)
        app_logger.info(f"Successfully created statement: {repr(main_statement)}")
        return self._build_and_output_response()

    def _create_statement_and_output(self):
        relation = self.context.relation
        if self.context.relation and self.context.relation.is_of_type(RelationshipType.DO):
            complement_caption_rest = self.context.complement_caption_rest or self.context.complement_notion_expression.caption
        else:
            complement_caption_rest = self.context.complement_notion_expression.caption
        complement_expression = NotionExpression(caption=complement_caption_rest) if complement_caption_rest else self.context.complement_notion_expression
        complement_notion = self._notion_service.find_or_create(
            self.context.user_agent.user_id,
            self.context.user_agent.agent_id,
            complement_expression,
        )
        self._notify_notion_created(complement_notion)
        if self._is_notions_same(self.context.subject_notion, complement_notion):
            return self._output_forbidden_response()
        self._statement_service.create(
            user_id=self.context.user_agent.user_id,
            agent_id=self.context.user_agent.agent_id,
            subject_notion=self.context.subject_notion,
            relation=relation,
            complement_notion=complement_notion,
            probability=self.context.proposed_probability,
            validity=self.context.proposed_validity,
            modifier=self.context.modifier,
        )
        return self._build_and_output_response()

    def _generate_statement_hierarchy(self):
        subject_expression = self.context.subject_notion_expression
        complement_expression = self.context.complement_notion_expression

        if subject_expression and subject_expression.children:
            statements = []
            for child_expression in subject_expression.children:
                child_notion = self._notion_service.find_or_create(
                    self.context.user_agent.user_id,
                    self.context.user_agent.agent_id,
                    child_expression
                )
                self._notify_notion_created(child_notion)
                if self._is_notions_same(child_notion, self.context.complement_notion):
                    return None
                statement = self._create_statement_for_pair(child_notion, self.context.complement_notion)
                statements.append(statement)
            return statements[0] if statements else None

        if complement_expression and complement_expression.children:
            statements = []
            for child_expression in complement_expression.children:
                child_notion = self._notion_service.find_or_create(
                    self.context.user_agent.user_id,
                    self.context.user_agent.agent_id,
                    child_expression
                )
                self._notify_notion_created(child_notion)
                if self._is_notions_same(self.context.subject_notion, child_notion):
                    return None
                statement = self._create_statement_for_pair(self.context.subject_notion, child_notion)
                statements.append(statement)
            return statements[0] if statements else None

        return self._create_statement_for_pair(self.context.subject_notion, self.context.complement_notion)

    def _store_statement_in_context(self, statement):
        self.context.statement = statement

    def _create_statement_for_pair(self, subject_notion, complement_notion):
        if self._is_notions_same(subject_notion, complement_notion):
            return None
        relation = self.context.relation
        return self._statement_service.create(
            user_id=self.context.user_agent.user_id,
            agent_id=self.context.user_agent.agent_id,
            subject_notion=subject_notion,
            relation=relation,
            complement_notion=complement_notion,
            probability=self.context.proposed_probability,
            validity=self.context.proposed_validity,
            modifier=self.context.modifier,
        )

    def _is_subject_object_same(self):
        return self._is_notions_same(self.context.subject_notion, self.context.complement_notion)

    def _is_notions_same(self, subject_notion, complement_notion):
        if subject_notion is None or complement_notion is None:
            return False
        return subject_notion.id == complement_notion.id

    def _notify_notion_created(self, notion) -> None:
        if notion is None:
            return
        try:
            from analogai.deepthink.config import NOTION_ENRICHMENT_ENABLED
            if not NOTION_ENRICHMENT_ENABLED:
                return
            from analogai.deepthink.features.notion_enrichment.registry import get_notion_enrichment_observer
            observer = get_notion_enrichment_observer()
            if observer is None:
                return
            observer.on_notion_created(notion)
        except Exception:
            return

    def _output_forbidden_response(self):
        response = self._response_builder.build_response()
        return self._output_port.output_forbidden(response)

    def _build_and_output_response(self):
        response = self._response_builder.build_response()
        return self._output_port.output_create_statement_success(response)

