from __future__ import annotations

from typing import Any, List, Literal, Optional, Tuple

from pydantic import BaseModel, Field

ChartType = Literal["bar", "line", "pie"]


class FilterSpec(BaseModel):
    dimension: str
    op: Literal["=", "!=", "in", "between", ">", "<", ">=", "<="] = "="
    value: Any = None
    value_end: Any = None  # for between


class QueryIntent(BaseModel):
    """Structured intent produced from NL; drives SQL generation."""

    entity: str = "orders"
    metrics: List[str] = Field(default_factory=lambda: ["revenue"])
    dimensions: List[str] = Field(default_factory=list)
    filters: List[FilterSpec] = Field(default_factory=list)
    time_range: Optional[Tuple[Optional[str], Optional[str]]] = None  # inclusive ISO dates
    order_by: Optional[str] = None  # metric or dimension name
    limit: Optional[int] = 500
    reasoning: str = ""


class ChatMessage(BaseModel):
    role: Literal["user", "assistant", "system"]
    content: str


class ChatRequest(BaseModel):
    message: str
    session_id: Optional[str] = None


class SqlExecutionResult(BaseModel):
    sql: str
    columns: List[str]
    rows: List[List[Any]]
    row_count: int
    truncated: bool = False


class ChartDataset(BaseModel):
    label: str
    data: List[float]


class ChartPayload(BaseModel):
    """Structured series for Chart.js (bar, line, pie) in the client."""

    title: str
    labels: List[str]
    datasets: List[ChartDataset]
    default_chart: ChartType = "bar"
    suggested_types: List[ChartType] = Field(default_factory=lambda: ["bar", "line", "pie"])


class ChatResponse(BaseModel):
    session_id: str
    answer_markdown: str
    intent: QueryIntent
    execution: SqlExecutionResult
    used_llm: bool = False
    chart: Optional[ChartPayload] = None
