from __future__ import annotations

from typing import Literal

from fastapi import APIRouter, HTTPException
from pydantic import BaseModel, Field, field_validator

from app.core.config import settings
from app.retrieval.models import RetrieveRequest, RetrieveResponse
from app.retrieval.retrieval_service import retrieve

router = APIRouter(tags=["Search"])


class SearchRequest(BaseModel):
    prompt: str = Field(..., min_length=1, description="Natural language query")
    top_k: int = Field(default=5, ge=1, le=50)
    source_types: list[Literal["code", "docs", "commit"]] | None = None

    @field_validator("prompt")
    @classmethod
    def _strip(cls, v: str) -> str:
        stripped = v.strip()
        if not stripped:
            raise ValueError("prompt must not be blank")
        return stripped


class SearchResponse(BaseModel):
    query: str
    repo_id: str
    snapshot_id: str
    results: RetrieveResponse


@router.post("/search", response_model=SearchResponse, response_model_exclude_none=True)
async def search(body: SearchRequest) -> SearchResponse:
    """
    Search indexed data in Qdrant using a natural language prompt.
    repo_id and snapshot_id are read from SEARCH_DEFAULT_REPO_ID / SEARCH_DEFAULT_SNAPSHOT_ID env vars.
    """
    repo_id = settings.SEARCH_DEFAULT_REPO_ID
    snapshot_id = settings.SEARCH_DEFAULT_SNAPSHOT_ID

    if not repo_id or not snapshot_id:
        raise HTTPException(
            status_code=503,
            detail="SEARCH_DEFAULT_REPO_ID and SEARCH_DEFAULT_SNAPSHOT_ID must be set in the environment",
        )

    req = RetrieveRequest(
        repo_id=repo_id,
        snapshot_id=snapshot_id,
        query_text=body.prompt,
        top_k=body.top_k,
        filters={"source_types": body.source_types} if body.source_types else None,
    )
    result = await retrieve(req)
    return SearchResponse(query=body.prompt, repo_id=repo_id, snapshot_id=snapshot_id, results=result)
