"""Chat routing policy — channel selection after primary intent classification.

Primary intents (see intent_router.py):
  document_lookup | document_metadata | general_knowledge | calculation | conversational

Maps those into concrete answer targets (templates / calculator / Ollama / structured KB).
"""

from __future__ import annotations

import re
from dataclasses import dataclass
from typing import Literal

from app.saas.conversation import ResolvedTurn
from app.saas.finance_intent import classify_finance_intent
from app.saas.intent_router import (
    PrimaryIntent,
    classify_primary_intent,
    is_ask_first_question,
    is_ask_my_name,
    is_document_metadata_question,
    is_general_knowledge_question,
    is_self_intro,
    is_today_date_question,
    primary_uses_kb_inventory,
    primary_uses_retrieval,
)

# Re-export for agent / tests
__all__ = [
    "ChatRoute",
    "PrimaryIntent",
    "classify_primary_intent",
    "is_ask_first_question",
    "is_ask_my_name",
    "is_document_metadata_question",
    "is_general_knowledge_question",
    "is_general_llm_question",
    "is_ollama_concept",
    "is_self_intro",
    "is_today_date_question",
    "needs_document_grounding",
    "route_chat",
    "route_summary",
]
from app.rag.chain import (
    _HOW_ARE_YOU_RE,
    _normalize_smalltalk,
)

RouteTarget = Literal[
    "template_greeting",
    "template_how_are_you",
    "template_thanks",
    "template_bye",
    "template_offtopic",
    "template_help",
    "template_clarify",
    "template_personal",
    "template_today",
    "calculator",
    "ollama_concept",
    "structured_or_rag",
    "kb_metadata",
]


@dataclass(frozen=True)
class ChatRoute:
    """Decision for one user turn."""

    target: RouteTarget
    chat_intent: str
    finance_intent: str
    use_docs: bool
    use_ollama: bool
    reason: str
    primary_intent: PrimaryIntent = "conversational"


def needs_document_grounding(question: str, finance_intent: str, chat_intent: str) -> bool:
    """True when the answer must be grounded in uploaded statement *contents*."""
    primary = classify_primary_intent(question, finance_intent=finance_intent)
    return primary_uses_retrieval(primary.intent)


def is_ollama_concept(question: str) -> bool:
    return is_general_knowledge_question(question)


def is_general_llm_question(question: str) -> bool:
    return is_general_knowledge_question(question)


def route_chat(
    question: str,
    *,
    resolved: ResolvedTurn | None = None,
    finance_intent: str | None = None,
    chat_intent: str | None = None,
) -> ChatRoute:
    """Pick the answer channel for this turn using the 5-way primary intent."""
    q = (question or "").strip()
    original = (resolved.original if resolved else q) or q
    rewritten = (resolved.rewritten if resolved else q) or q

    fin = finance_intent or classify_finance_intent(original)
    if fin == "general" and rewritten != original:
        # Follow-ups may expand into document asks via rewrite
        if resolved and resolved.conv_intent in {"follow_up", "verify", "explain_calc"}:
            fin = classify_finance_intent(rewritten)

    # Prefer rewritten wording only for follow-ups when classifying primary intent
    classify_q = original
    if (
        resolved
        and resolved.conv_intent in {"follow_up", "verify", "explain_calc"}
        and rewritten != original
    ):
        classify_q = rewritten

    primary = classify_primary_intent(classify_q, finance_intent=fin)
    # Follow-up document challenges stay on document_lookup
    if (
        resolved
        and resolved.conv_intent in {"follow_up", "verify", "explain_calc"}
        and primary.intent in {"conversational", "general_knowledge"}
        and classify_finance_intent(rewritten) not in {"general"}
    ):
        primary = classify_primary_intent(rewritten, finance_intent=classify_finance_intent(rewritten))

    fin = primary.finance_intent
    chat = chat_intent or primary.chat_intent
    norm = _normalize_smalltalk(original)

    # ── 4) Calculation ───────────────────────────────────────────────────────
    if primary.intent == "calculation":
        from app.rag.calculator import is_pure_math

        if is_pure_math(original):
            return ChatRoute(
                "calculator",
                "math",
                fin,
                False,
                False,
                primary.reason,
                primary.intent,
            )
        # Hypotheticals → Ollama (no RAG); model can reason over prior figures in history
        return ChatRoute(
            "ollama_concept",
            "concept",
            fin,
            False,
            True,
            primary.reason + " → base LLM",
            primary.intent,
        )

    # ── 5) Conversational ────────────────────────────────────────────────────
    if primary.intent == "conversational":
        if is_today_date_question(original):
            return ChatRoute(
                "template_today",
                "greeting",
                "general",
                False,
                False,
                "today's date",
                primary.intent,
            )
        if is_self_intro(original) or is_ask_my_name(original) or is_ask_first_question(original):
            return ChatRoute(
                "template_personal",
                "greeting",
                "general",
                False,
                False,
                "conversation memory",
                primary.intent,
            )
        from app.saas.personality import is_capability_question, is_identity_question

        if is_identity_question(original) or is_capability_question(original) or chat == "help":
            return ChatRoute(
                "template_help", "help", "general", False, False, "capability / identity", primary.intent
            )
        if "unrelated third-party" in primary.reason:
            return ChatRoute(
                "template_offtopic",
                "offtopic",
                "general",
                False,
                False,
                primary.reason,
                primary.intent,
            )
        if _HOW_ARE_YOU_RE.match(norm) or "how are you" in norm:
            return ChatRoute(
                "template_how_are_you",
                "greeting",
                "general",
                False,
                False,
                "wellbeing check-in",
                primary.intent,
            )
        if chat == "thanks":
            return ChatRoute(
                "template_thanks", "thanks", "general", False, False, "thanks", primary.intent
            )
        if chat == "bye":
            return ChatRoute(
                "template_bye", "bye", "general", False, False, "goodbye", primary.intent
            )
        if chat == "greeting" or _HOW_ARE_YOU_RE.match(norm):
            return ChatRoute(
                "template_greeting",
                "greeting",
                "general",
                False,
                False,
                "greeting",
                primary.intent,
            )
        return ChatRoute(
            "template_clarify",
            "help",
            "general",
            False,
            False,
            primary.reason or "clarify",
            primary.intent,
        )

    # ── 3) General knowledge ─────────────────────────────────────────────────
    if primary.intent == "general_knowledge":
        return ChatRoute(
            "ollama_concept",
            "concept",
            "general",
            False,
            True,
            primary.reason,
            primary.intent,
        )

    # ── 2) Document metadata — inventory only (no Chroma content RAG) ────────
    if primary.intent == "document_metadata" or primary_uses_kb_inventory(primary.intent):
        return ChatRoute(
            "kb_metadata",
            "data",
            "document_qa",
            True,
            False,
            primary.reason,
            primary.intent,
        )

    # ── 1) Document lookup — structured statement / Chroma when needed ───────
    if primary.intent == "document_lookup" or primary_uses_retrieval(primary.intent):
        return ChatRoute(
            "structured_or_rag",
            "data",
            fin,
            True,
            True,
            primary.reason,
            primary.intent,
        )

    return ChatRoute(
        "template_clarify",
        "help",
        "general",
        False,
        False,
        "fallback clarify",
        "conversational",
    )


def route_summary() -> str:
    return (
        "I can help with your uploaded statements (spend, merchants, dates), "
        "answer general questions, or do quick math — what would you like?"
    )
