from __future__ import annotations

from typing import Optional

from analogai.foundation.settings import config as infra_config
from analogai.foundation.settings import config as app_config
from analogai.deepthink.infrastructure.gateways.llm.gateway import LlmGateway
from analogai.foundation.common.logging.app_logger import app_logger
from analogai.deepthink.infrastructure.gateways.llm.llm_gateway_provider_factory import LlmGatewayProviderFactory
from analogai.deepthink.infrastructure.gateways.llm.enums.llm_provider import LlmProvider
from analogai.deepthink.messaging.question_answering.qa_synthesizer_prompt_composer import (
    QASynthesizerPromptComposer,
)
from analogai.deepthink.messaging.question_answering.question_answering_service import (
    QuestionAnsweringService,
)
from analogai.foundation.modules.fact.services.fact_service import FactServicePort
from analogai.deepthink.messaging.fact.enums.fact_search_mode import FactSearchMode


def _resolve_provider(value: str | LlmProvider | None) -> LlmProvider | None:
    if value is None:
        return None
    if isinstance(value, LlmProvider):
        return value
    normalized = str(value).strip().lower().replace("-", "_")
    if not normalized:
        return None
    legacy_map = {
        "claude": LlmProvider.ANTHROPIC,
        "azureopenai": LlmProvider.AZURE_OPENAI,
        "xai": LlmProvider.XAI,
    }
    if normalized in legacy_map:
        return legacy_map[normalized]
    return LlmProvider(normalized)


def create_question_answering_service(
    domain_service_factory,
    llm_gateway_instance: Optional[LlmGateway] = None,
    fact_context_assembler=None,
    fact_context_service=None,
    fact_service=None,
) -> QuestionAnsweringService:
    rag_similarity_cutoff = app_config.get(
        "vector_search.rag_similarity_cutoff",
        app_config.get(
            "vector_search.fact_similarity_cutoff",
            app_config.get(
                "vector_search.graph_similarity_cutoff",
                app_config.get(
                    "vector_search.similarity_cutoff",
                    infra_config.get(
                        "FACT_SIMILARITY_CUTOFF",
                        infra_config.get("vector.cutoff", 0.25),
                    ),
                ),
            ),
        ),
    )
    fact_search_top_k = app_config.get(
        "qa.graph_search_top_k",
        app_config.get("qa.fact_search_top_k", 5),
    )
    use_vector_search = bool(app_config.get("vector_search.enabled", True))
    search_mode = (
        FactSearchMode.VECTOR_THEN_TEXT
        if use_vector_search
        else FactSearchMode.TEXT_ONLY
    )
    belief_service = domain_service_factory.get_belief_service()
    notion_service = domain_service_factory.get_notion_service()
    fact_retriever: FactServicePort | None = fact_service
    retriever_label = type(fact_retriever).__name__ if fact_retriever is not None else "none"
    app_logger.debug(
        "[QA Factory] fact_retriever=%s",
        retriever_label,
    )
    prompt_builder = QASynthesizerPromptComposer()
    system_prompt = prompt_builder.build_system_prompt()

    qa_max_tokens = app_config.get("qa.max_tokens", 4000)
    qa_synthesizer_max_tokens = app_config.get("qa.synthesizer_max_tokens", qa_max_tokens)
    raw_answer_enabled = bool(app_config.get("qa.raw_answer_enabled", False))

    if llm_gateway_instance is not None:
        llm_gateway_instance.set_system_prompt(system_prompt)
        llm_gateway = llm_gateway_instance
    else:
        if raw_answer_enabled:
            llm_gateway = LlmGatewayProviderFactory.create_gateway(
                system_prompt=system_prompt,
                max_tokens=qa_max_tokens,
            )
        else:
            preprocessing_provider = _resolve_provider(
                app_config.get(
                    "llm.preprocessing.provider",
                    app_config.get("llm.sentence_transformer.provider"),
                )
            )
            preprocessing_model = app_config.get(
                "llm.preprocessing.model",
                app_config.get("llm.sentence_transformer.model"),
            )
            if preprocessing_provider or preprocessing_model:
                llm_gateway = LlmGatewayProviderFactory.create_gateway(
                    gateway_type=preprocessing_provider,
                    model=preprocessing_model or None,
                    system_prompt=system_prompt,
                    max_tokens=qa_max_tokens,
                )
            else:
                llm_gateway = LlmGatewayProviderFactory.create_gateway(
                    gateway_type=LlmProvider.FAKE,
                    model="noop",
                    system_prompt=system_prompt,
                    max_tokens=qa_max_tokens,
                )

    synthesizer_override = any(
        app_config.get(key)
        for key in (
            "llm.qa_synthesizer.exact_match_provider",
            "llm.qa_synthesizer.exact_match_model",
            "llm.qa_synthesizer.detailed_provider",
            "llm.qa_synthesizer.detailed_model",
        )
    )
    synthesizer_gateway = None
    if not synthesizer_override:
        synthesizer_gateway = LlmGatewayProviderFactory.create_gateway(
            system_prompt="",
            max_tokens=qa_synthesizer_max_tokens,
        )

    return QuestionAnsweringService(
        belief_service=belief_service,
        notion_service=notion_service,
        llm_gateway=llm_gateway,
        synthesizer_gateway=synthesizer_gateway,
        fact_context_assembler=fact_context_assembler,
        fact_context_service=fact_context_service,
        prompt_builder=prompt_builder,
        fact_retriever=fact_retriever,
    )
