from __future__ import annotations

from typing import Iterable, List, Optional

from analogai.deepthink.messaging.fact.services.fact_context_service import FactContextWindowService
from analogai.foundation.modules.fact.fact_source import FactSource
from analogai.foundation.common.logging.app_logger import app_logger
from analogai.deepthink.messaging.text.sentence_chunker import split_into_sentences


class AnswerFactAssembler:
    def __init__(self, fact_context_service: Optional[FactContextWindowService] = None) -> None:
        self._fact_context_service = fact_context_service

    def build_fact_sections(
        self,
        beliefs: Iterable,
        belief_lines: Iterable[str],
        notion_lines: Iterable[str],
        fact_lookup: dict[str, str],
        source_lookup: dict[str, FactSource] | None,
        context_lookup: dict[str, list[str]] | None,
        raw_answer: str,
        qa_history: str,
        user_history_block: str,
        include_raw_answer: bool = True,
    ) -> tuple[str, str]:
        items: List[str] = []
        background_items: List[str] = []
        background_seen: set[str] = set()
        for belief_line in belief_lines or []:
            cleaned = _sanitize_fact_line(belief_line)
            if not cleaned:
                continue
            _extend_fact_items(items, cleaned)
            key = cleaned.casefold()
            if key not in background_seen:
                background_seen.add(key)
                _append_fact_item(background_items, cleaned)
        for notion_line in notion_lines or []:
            cleaned = _sanitize_fact_line(notion_line)
            if not cleaned:
                continue
            _extend_fact_items(items, cleaned)
            key = cleaned.casefold()
            if key not in background_seen:
                background_seen.add(key)
                _append_fact_item(background_items, cleaned)
        if beliefs and self._fact_context_service is not None:
            for belief in beliefs:
                context_lines = self._fact_context_service.build_fact_context(belief)
                for line in context_lines:
                    cleaned = _sanitize_fact_line(line)
                    if not cleaned:
                        continue
                    key = cleaned.casefold()
                    if key in background_seen:
                        continue
                    background_seen.add(key)
                    _append_fact_item(background_items, cleaned)
        if fact_lookup:
            for fact_key, fact_text in fact_lookup.items():
                cleaned = _sanitize_fact_line(fact_text)
                if not cleaned:
                    continue
                source_suffix = _format_fact_source_suffix(
                    source_lookup.get(fact_key) if source_lookup else None
                )
                if source_suffix:
                    _extend_fact_items(items, cleaned, source_suffix=source_suffix)
                else:
                    _extend_fact_items(items, cleaned)
                try:
                    app_logger.debug(
                        "[AnswerFactAssembler] fact added to facts id=%s value=%s",
                        fact_key,
                        cleaned,
                    )
                except Exception:
                    pass
                key = cleaned.casefold()
                if key not in background_seen:
                    background_seen.add(key)
                    _append_fact_item(background_items, cleaned)
                if context_lookup and fact_key in context_lookup:
                    context_lines = context_lookup.get(fact_key, [])
                    for line in context_lines:
                        cleaned_context = _sanitize_fact_line(line)
                        if not cleaned_context:
                            continue
                        key = cleaned_context.casefold()
                        if key in background_seen:
                            continue
                        background_seen.add(key)
                        _append_fact_item(background_items, cleaned_context)
        facts_block = "\n".join(f"{index}) {item}" for index, item in enumerate(items, start=1)) if items else ""
        background_block = "\n".join(background_items) if background_items else ""
        return facts_block, background_block

    def build_fact_block(
        self,
        beliefs: Iterable,
        belief_lines: Iterable[str],
        notion_lines: Iterable[str],
        fact_lookup: dict[str, str],
        source_lookup: dict[str, FactSource] | None,
        raw_answer: str,
        qa_history: str,
        user_history_block: str,
        include_raw_answer: bool = True,
    ) -> str:
        facts_block, _ = self.build_fact_sections(
            beliefs=beliefs,
            belief_lines=belief_lines,
            notion_lines=notion_lines,
            fact_lookup=fact_lookup,
            source_lookup=source_lookup,
            context_lookup=None,
            raw_answer=raw_answer,
            qa_history=qa_history,
            user_history_block=user_history_block,
            include_raw_answer=include_raw_answer,
        )
        return facts_block


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 _sanitize_fact_line(text: str) -> str:
    if not text:
        return ""
    cleaned = str(text).strip()
    if "A:" in cleaned:
        cleaned = cleaned.rsplit("A:", 1)[-1].strip()
        cleaned = cleaned.lstrip("|-–— ")
    if not cleaned:
        return ""
    if _looks_like_question(cleaned):
        return ""
    return cleaned


def _normalize_fact_line(text: str) -> str:
    normalized = text.strip().lower()
    if normalized.startswith("-"):
        normalized = normalized.lstrip("- ")
    return normalized


def _append_fact_item(items: List[str], item: str) -> None:
    items.append(item)


def _extend_fact_items(items: List[str], text: str, source_suffix: str | None = None) -> None:
    sentences = split_into_sentences(text)
    if not sentences:
        cleaned = text.strip()
        if cleaned:
            _append_fact_item(items, _append_source_suffix(cleaned, source_suffix))
        return
    for sentence in sentences:
        cleaned = sentence.strip()
        if not cleaned:
            continue
        _append_fact_item(items, _append_source_suffix(cleaned, source_suffix))


def _append_source_suffix(text: str, source_suffix: str | None) -> str:
    if not source_suffix:
        return text
    if _contains_source(text):
        return text
    return f"{text} {source_suffix}".strip()


def _contains_source(text: str) -> bool:
    lowered = text.lower()
    return "source:" in lowered or "http://" in lowered or "https://" in lowered


def _format_fact_source_suffix(source: FactSource | None) -> str:
    if not source:
        return ""
    value = source.resolve_value() if hasattr(source, "resolve_value") else str(source)
    value = (value or "").strip()
    if not value:
        value = str(source)
    if not value:
        return ""
    return f"(Source: {value})"
