from __future__ import annotations

from typing import Iterable

from analogai.deepthink.application.value_objects.user_agent import UserAgent
from analogai.deepthink.messaging.question_answering.adapters.fact_search_adapter import (
    FactSearchAdapter,
)
from analogai.deepthink.messaging.fact.enums.fact_search_mode import FactSearchMode
from analogai.foundation.common.logging.app_logger import app_logger  # type: ignore[import-not-found]


class FactRetrievalCommand:
    def __init__(self, fact_retriever: FactSearchAdapter | None = None) -> None:
        self._fact_retriever = fact_retriever

    def execute(
        self,
        user_agent: UserAgent,
        question_text: str,
        entities: Iterable[str] | None,
        notions: Iterable | None,
        allow_question_facts: bool,
        search_mode: FactSearchMode,
        lookup: dict[str, str] | None = None,
    ) -> dict[str, str]:
        if not self._fact_retriever:
            return {}
        retriever = self._fact_retriever
        if lookup is None:
            lookup = {}
        self._find_by_notions(
            retriever,
            notions,
            lookup,
            allow_questions=allow_question_facts,
        )
        self._find_by_entities(
            retriever,
            user_agent,
            entities,
            lookup,
            allow_questions=allow_question_facts,
            search_mode=search_mode,
        )
        self._find_direct(
            retriever,
            user_agent,
            question_text,
            lookup,
            allow_questions=allow_question_facts,
            search_mode=search_mode,
        )
        return lookup

    def _find_by_notions(
        self,
        retriever: FactSearchAdapter,
        notions: Iterable | None,
        lookup: dict[str, str],
        allow_questions: bool,
    ) -> None:
        for notion in notions or []:
            if notion is None:
                continue
            notion_id = _notion_id(notion)
            if not notion_id:
                continue
            facts = retriever.get_facts_for_notion(notion_id)
            self._append_facts(facts, lookup, allow_questions=allow_questions)

    def _find_by_entities(
        self,
        retriever: FactSearchAdapter,
        user_agent: UserAgent,
        entities: Iterable[str] | None,
        lookup: dict[str, str],
        allow_questions: bool,
        search_mode: FactSearchMode,
    ) -> None:
        for entity in entities or []:
            if not entity:
                continue
            query = str(entity).strip()
            if not query:
                continue
            facts = retriever.search_facts(
                user_agent,
                query,
                search_mode=search_mode,
            )
            self._append_facts(facts, lookup, allow_questions=allow_questions)

    def _find_direct(
        self,
        retriever: FactSearchAdapter,
        user_agent: UserAgent,
        question_text: str,
        lookup: dict[str, str],
        allow_questions: bool,
        search_mode: FactSearchMode,
    ) -> None:
        if not question_text or not question_text.strip():
            return
        facts = retriever.search_facts(
            user_agent,
            question_text,
            search_mode=search_mode,
        )
        self._append_facts(facts, lookup, allow_questions=allow_questions)

    @staticmethod
    def _append_facts(
        facts: Iterable,
        lookup: dict[str, str],
        allow_questions: bool,
    ) -> None:
        for fact in facts or []:
            text = fact.text
            if not text:
                continue
            cleaned = str(text).strip()
            if not cleaned:
                continue
            if not allow_questions and _looks_like_question(cleaned):
                continue
            fact_key = fact.id
            if fact_key is None:
                continue
            key = str(fact_key)
            if key in lookup:
                continue
            lookup[key] = cleaned
            app_logger.debug(
                "[FactRetrievalCommand] fact added to lookup id=%s text=%s",
                key,
                cleaned,
            )


def _looks_like_question(text: str) -> bool:
    if "?" in text:
        return True
    lowered = text.strip().lower()
    return lowered.startswith("q:") or lowered.startswith("question:")


def _notion_id(notion) -> str | None:
    if notion is None:
        return None
    return str(notion.id)
