from typing import Annotated, Literal

from fastapi import APIRouter, Depends, File, Query, Request, Response, UploadFile, status
from sqlalchemy.ext.asyncio import AsyncSession

from kbqa.api.errors import AppError
from kbqa.database import get_session
from kbqa.documents.repository import DocumentRepository
from kbqa.documents.schemas import ChunkResponse, DocumentResponse, Page
from kbqa.documents.service import DocumentService

router = APIRouter(prefix="/documents", tags=["documents"])

SessionDependency = Annotated[AsyncSession, Depends(get_session)]


def get_document_service(request: Request) -> DocumentService:
    return request.app.state.document_service


@router.post("", response_model=DocumentResponse, status_code=status.HTTP_202_ACCEPTED)
async def upload_document(
    file: Annotated[UploadFile, File()],
    service: Annotated[DocumentService, Depends(get_document_service)],
) -> DocumentResponse:
    document = await service.upload(file)
    return DocumentResponse.model_validate(document)


@router.get("", response_model=Page[DocumentResponse])
async def list_documents(
    session: SessionDependency,
    document_status: Annotated[
        Literal["pending", "indexing", "indexed", "failed", "deleting"] | None,
        Query(alias="status"),
    ] = None,
    offset: Annotated[int, Query(ge=0)] = 0,
    limit: Annotated[int, Query(ge=1, le=100)] = 20,
) -> Page[DocumentResponse]:
    items, total = await DocumentRepository(session).page(document_status, offset, limit)
    return Page(
        items=[DocumentResponse.model_validate(item) for item in items],
        total=total,
        offset=offset,
        limit=limit,
    )


@router.get("/{document_id}", response_model=DocumentResponse)
async def get_document(document_id: str, session: SessionDependency) -> DocumentResponse:
    document = await DocumentRepository(session).get(document_id)
    if document is None:
        raise AppError("DOCUMENT_NOT_FOUND", "文档不存在", 404)
    return DocumentResponse.model_validate(document)


@router.get("/{document_id}/chunks", response_model=Page[ChunkResponse])
async def list_document_chunks(
    document_id: str,
    session: SessionDependency,
    offset: Annotated[int, Query(ge=0)] = 0,
    limit: Annotated[int, Query(ge=1, le=100)] = 20,
) -> Page[ChunkResponse]:
    repository = DocumentRepository(session)
    if await repository.get(document_id) is None:
        raise AppError("DOCUMENT_NOT_FOUND", "文档不存在", 404)
    items, total = await repository.page_chunks(document_id, offset, limit)
    return Page(
        items=[ChunkResponse.model_validate(item) for item in items],
        total=total,
        offset=offset,
        limit=limit,
    )


@router.post(
    "/{document_id}/retry",
    response_model=DocumentResponse,
    status_code=status.HTTP_202_ACCEPTED,
)
async def retry_document(
    document_id: str,
    service: Annotated[DocumentService, Depends(get_document_service)],
) -> DocumentResponse:
    document = await service.retry(document_id)
    return DocumentResponse.model_validate(document)


@router.delete("/{document_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_document(
    document_id: str,
    service: Annotated[DocumentService, Depends(get_document_service)],
) -> Response:
    await service.delete(document_id)
    return Response(status_code=status.HTTP_204_NO_CONTENT)
