from __future__ import annotations

from dataclasses import dataclass, field
from datetime import datetime

from tests.pipeline_setup.suite_02_pipeline.pipeline_intent_rag.helpers.result_views import PipelineDiagnosticsBuilder, PipelineSummaryBuilder


@dataclass(slots=True)
class PhraseCase:
    case_id: str
    text: str
    rag_session_id: str | None = None
    tags: list[str] = field(default_factory=list)
    expected_intent: str | None = None
    expect_non_empty_rag: bool = True


@dataclass(slots=True)
class PipelineResult:
    case: PhraseCase
    mode: str
    run_started_at: datetime
    rag_session_id: str | None
    intent: str
    graph_id: str
    conversation_mode: str
    query: str
    symbol_resolution: dict
    rag_rows: list[dict] = field(default_factory=list)
    llm_answer: str | None = None
    diagnostics: dict = field(default_factory=dict)
    steps: list[dict] = field(default_factory=list)

    def to_record(self) -> dict:
        diagnostics = PipelineDiagnosticsBuilder().build(self)
        summary = PipelineSummaryBuilder().build(self, diagnostics)
        steps = self.steps or self._default_steps(diagnostics)
        return {
            "case_id": self.case.case_id,
            "text": self.case.text,
            "mode": self.mode,
            "run_started_at": self.run_started_at.isoformat(timespec="seconds"),
            "rag_session_id": self.rag_session_id,
            "expected_intent": self.case.expected_intent,
            "actual_intent": self.intent,
            "graph_id": self.graph_id,
            "conversation_mode": self.conversation_mode,
            "query": self.query,
            "symbol_resolution": self.symbol_resolution,
            "rag_count": len(self.rag_rows),
            "rag_rows": self.rag_rows,
            "llm_answer": self.llm_answer,
            "summary": summary,
            "diagnostics": diagnostics,
            "run_info": {
                "case_id": self.case.case_id,
                "mode": self.mode,
                "run_started_at": self.run_started_at.isoformat(timespec="seconds"),
                "rag_session_id": self.rag_session_id,
                "expected_intent": self.case.expected_intent,
                "actual_intent": self.intent,
                "graph_id": self.graph_id,
                "conversation_mode": self.conversation_mode,
            },
            "input_request": {
                "text": self.case.text,
                "normalized_query": self.query,
            },
            "steps": steps,
        }

    def _default_steps(self, diagnostics: dict) -> list[dict]:
        timings = dict(diagnostics.get("timings_ms") or {})
        retrieval_diag = diagnostics.get("retrieval")
        router_step = {
            "step": "intent_router",
            "input": {"query": self.case.text},
            "output": {
                "intent": self.intent,
                "graph_id": self.graph_id,
                "conversation_mode": self.conversation_mode,
                "query": self.query,
            },
            "diagnostics": {
                "router_plan": diagnostics.get("router_plan"),
                "timings_ms": {"router": timings.get("router", 0)},
            },
        }
        if self.mode == "router_only":
            return [router_step]
        retrieval_step = {
            "step": "retrieval",
            "input": {"query": self.query},
            "output": {
                "symbol_resolution": self.symbol_resolution,
                "rag_count": len(self.rag_rows),
                "rag_rows": self.rag_rows,
            },
            "diagnostics": {
                "execution": diagnostics.get("execution"),
                "retrieval": retrieval_diag,
                "constraint_violations": diagnostics.get("constraint_violations"),
                "timings_ms": {
                    "symbol_resolution": timings.get("symbol_resolution", 0),
                    "retrieval_total": timings.get("retrieval_total", 0),
                    "retrieval_by_layer": timings.get("retrieval_by_layer", {}),
                    "merge_rank": timings.get("merge_rank", 0),
                },
            },
        }
        if self.mode == "router_rag":
            return [router_step, retrieval_step]
        llm_step = {
            "step": "llm_answer",
            "input": {"query": self.query, "rag_count": len(self.rag_rows)},
            "output": {"llm_answer": self.llm_answer},
            "diagnostics": {
                "prompt": diagnostics.get("prompt"),
                "timings_ms": {
                    "prompt_build": timings.get("prompt_build", 0),
                    "llm_call": timings.get("llm_call", 0),
                },
            },
        }
        return [router_step, retrieval_step, llm_step]
