from __future__ import annotations

from datetime import datetime
from typing import Literal

from pydantic import Field

from app.models.common import StrictModel
from app.models.context import Citation
from app.models.internal_retrieve import SourceType
from app.models.search import SearchOptions, SearchRequest, SearchResponse


DEFAULT_DELIVERABLE_MAX_BYTES = 262_144


class DeliverableOptions(StrictModel):
    enabled: bool = False
    format: Literal["markdown"] = "markdown"
    template: Literal[
        "freeform",
        "architecture_overview",
        "onboarding_guide",
        "change_summary",
        "api_reference",
    ] = "freeform"
    title: str | None = None
    include_citations: bool = True
    max_bytes: int = Field(
        default=DEFAULT_DELIVERABLE_MAX_BYTES,
        ge=1,
        le=DEFAULT_DELIVERABLE_MAX_BYTES,
    )


class DocumentSourceRef(StrictModel):
    index: int
    record_id: str
    source_type: SourceType
    file_path: str | None = None
    doc_path: str | None = None
    commit_sha: str | None = None
    section_title: str | None = None
    symbol_name: str | None = None


class GeneratedDocument(StrictModel):
    id: str
    status: Literal["generated", "refused", "truncated", "failed"]
    format: Literal["markdown"]
    mime_type: Literal["text/markdown"]
    filename: str
    title: str
    template: str
    content: str | None = None
    byte_size: int
    sha256: str | None = None
    generated_at: datetime
    sources: list[DocumentSourceRef] = Field(default_factory=list)
    warnings: list[str] = Field(default_factory=list)


class QueryOptions(SearchOptions):
    stream: bool = False
    deliverable: DeliverableOptions | None = None
    include_reasoning: bool = False


class QueryRequest(SearchRequest):
    options: QueryOptions | None = None
    model: str | None = None


class ReasoningStep(StrictModel):
    step: int
    description: str
    used_indices: list[int] = Field(default_factory=list)


class QueryMetadata(StrictModel):
    latency_ms: int | None = None
    retrieval_count: int | None = None
    embedding_model: str | None = None
    model: str | None = None
    top_retrieval_score: float | None = None
    answer_mode: Literal["rag", "general"] | None = None
    intent_type: str | None = None
    retrieval_fallback_used: bool = False
    retrieval_fallback_pass: str | None = None


class QueryResponse(SearchResponse):
    answer: str | None = None
    citations: list[Citation] = Field(default_factory=list)
    reasoning: list[ReasoningStep] = Field(default_factory=list)
    deliverable: GeneratedDocument | None = None
    status: str | None = None
    message: str | None = None
    metadata: QueryMetadata = Field(default_factory=QueryMetadata)
