"""API routes for mykb daemon."""

import time
from typing import Optional

from fastapi import APIRouter, Request
from pydantic import BaseModel

from mykb.core.api import MykbAPI

router = APIRouter()


# --- Request/Response models ---


class EmbedDocumentsRequest(BaseModel):
    texts: list[str]


class EmbedDocumentsResponse(BaseModel):
    vectors: list[list[float]]


class EmbedQueryRequest(BaseModel):
    text: str


class EmbedQueryResponse(BaseModel):
    vector: list[float]


class IndexRequest(BaseModel):
    collection: str
    full: bool = False
    with_embeddings: bool = True


class IndexResponse(BaseModel):
    collection: str
    chunks: int
    elapsed: float


class EmbedCollectionRequest(BaseModel):
    collection: str
    full: bool = False


class EmbedCollectionResponse(BaseModel):
    collection: str
    updated: int


class SearchRequest(BaseModel):
    query: str
    limit: int = 10
    collection: Optional[str] = None


class HybridSearchRequest(BaseModel):
    query: str
    limit: int = 10
    collection: Optional[str] = None
    semantic_ratio: float = 0.5


class SearchHitModel(BaseModel):
    id: str
    score: float
    document: dict


class SearchResponse(BaseModel):
    hits: list[SearchHitModel]
    processing_time_ms: int


class HealthResponse(BaseModel):
    status: str
    model_loaded: bool
    model_name: str
    backend: str
    uptime: float


# --- Endpoints ---


def get_api(request: Request) -> MykbAPI:
    """Get MykbAPI instance from app state."""
    return request.app.state.api


@router.get('/health', response_model=HealthResponse)
async def health(request: Request):
    """Health check endpoint."""
    api = get_api(request)
    model_loaded = api.embedder is not None and api.embedder._model is not None
    uptime = time.time() - request.app.state.start_time

    return HealthResponse(
        status='ok',
        model_loaded=model_loaded,
        model_name=request.app.state.model_name,
        backend=request.app.state.backend_type,
        uptime=uptime,
    )


@router.post('/embed/documents', response_model=EmbedDocumentsResponse)
async def embed_documents(request: Request, body: EmbedDocumentsRequest):
    """Batch encode document texts into embedding vectors."""
    api = get_api(request)
    vectors = api.embed_documents(body.texts)
    return EmbedDocumentsResponse(vectors=vectors)


@router.post('/embed/query', response_model=EmbedQueryResponse)
async def embed_query(request: Request, body: EmbedQueryRequest):
    """Encode a search query into an embedding vector."""
    api = get_api(request)
    vector = api.embed_query(body.text)
    return EmbedQueryResponse(vector=vector)


@router.post('/collection/index', response_model=IndexResponse)
async def collection_index(request: Request, body: IndexRequest):
    """Index a collection with optional embeddings."""
    api = get_api(request)
    result = api.index(
        collection=body.collection,
        full=body.full,
        with_embeddings=body.with_embeddings,
    )
    return IndexResponse(
        collection=result['collection'],
        chunks=result['chunks'],
        elapsed=result['elapsed'],
    )


@router.post('/collection/embed', response_model=EmbedCollectionResponse)
async def collection_embed(request: Request, body: EmbedCollectionRequest):
    """Generate/update embeddings for an indexed collection."""
    api = get_api(request)
    result = api.embed_collection(body.collection, full=body.full)
    return EmbedCollectionResponse(
        collection=result['collection'],
        updated=result['updated'],
    )


@router.post('/search/vector', response_model=SearchResponse)
async def search_vector(request: Request, body: SearchRequest):
    """Vector semantic search."""
    api = get_api(request)
    result = api.search_vector(body.query, limit=body.limit, collection=body.collection)
    hits = [SearchHitModel(id=hit.id, score=hit.score, document=hit.document) for hit in result.hits]
    return SearchResponse(
        hits=hits,
        processing_time_ms=result.processing_time_ms,
    )


@router.post('/search/hybrid', response_model=SearchResponse)
async def search_hybrid(request: Request, body: HybridSearchRequest):
    """Hybrid search (BM25 + vector)."""
    api = get_api(request)
    result = api.search_hybrid(
        body.query,
        limit=body.limit,
        collection=body.collection,
        semantic_ratio=body.semantic_ratio,
    )
    hits = [SearchHitModel(id=hit.id, score=hit.score, document=hit.document) for hit in result.hits]
    return SearchResponse(
        hits=hits,
        processing_time_ms=result.processing_time_ms,
    )
