"""
VSS Response Composer
Assembles the final user-facing response from whichever pipeline handled the request.

Pipeline contract
-----------------
- SQL path (not escalated):
    The SQL agent's internal _finalize_answer node already ran the raw query
    result through the LLM and stored a complete English answer in
    state["sql_result_formatted"].  The composer must NOT re-process it — doing
    so would waste an LLM call and risk producing a contradictory answer.

- VLM path / escalated SQL:
    state["vlm_response"] contains the VLM prose.  The composer wraps it with
    escalation context when the SQL path found no data and handed off.

- Fallback / error:
    Best-effort assembly from whatever data is in state.
"""

import logging
from typing import Optional

from orchestration.state import VSSState, add_trace

logger = logging.getLogger(__name__)


class ResponseComposer:
    """Composes the final response written to state["final_response"]."""

    async def compose(self, state: VSSState) -> VSSState:
        """Select the correct composition strategy and write final_response."""
        add_trace(state, "Composer: Starting")

        source = state.get("response_source", "")

        try:
            if source == "sql" and not state.get("escalated"):
                response = self._compose_sql(state)
            elif source == "vlm" or state.get("vlm_response"):
                response = self._compose_vlm(state)
            else:
                response = self._compose_fallback(state)

            state["final_response"] = response
            add_trace(state, f"Composer: Done ({len(response)} chars)")

        except Exception as e:
            logger.error("Composition failed: %s", e)
            state["final_response"] = self._compose_error(state, str(e))

        return state

    # ── SQL path ──────────────────────────────────────────────────────────────

    def _compose_sql(self, state: VSSState) -> str:
        """
        Pass through the SQL agent's pre-composed natural-language answer.

        sql_result_formatted already contains the final English answer produced
        by SQLAgent._finalize_answer().  No additional formatting or LLM call
        is needed or desirable here.
        """
        formatted = state.get("sql_result_formatted", "")
        if formatted and formatted not in ("No results.", "No results found."):
            return formatted
        return "No data found for your query."

    # ── VLM path ──────────────────────────────────────────────────────────────

    def _compose_vlm(self, state: VSSState) -> str:
        """Compose from VLM response, optionally noting the SQL escalation reason."""
        vlm_response = state.get("vlm_response", "")
        if not vlm_response:
            return "Unable to analyze the visual content."

        if state.get("escalated"):
            reason = state.get("escalation_reason", "no matching data")
            return f"Based on visual analysis (SQL returned: {reason}):\n\n{vlm_response}"

        return vlm_response

    # ── Fallback / error paths ────────────────────────────────────────────────

    def _compose_fallback(self, state: VSSState) -> str:
        """Use whatever result data is available when the source is unclear."""
        if state.get("sql_result_formatted"):
            return state["sql_result_formatted"]
        if state.get("vlm_response"):
            return state["vlm_response"]
        return "I couldn't find relevant information. Please try rephrasing your question."

    def _compose_error(self, state: VSSState, error: str) -> str:
        """Compose a user-friendly error response."""
        return (
            f"I encountered an issue: {error}\n\n"
            "Suggestions:\n"
            "• Try specifying a time range (yesterday, last hour)\n"
            "• Ask about specific categories (cars, people, fire)\n"
            "• Upload an image for visual analysis"
        )


_composer: Optional[ResponseComposer] = None


def _get_composer() -> ResponseComposer:
    """Return the module-level ResponseComposer singleton (lazy init)."""
    global _composer
    if _composer is None:
        _composer = ResponseComposer()
    return _composer


async def compose_response(state: VSSState) -> VSSState:
    """LangGraph node function."""
    return await _get_composer().compose(state)
