"""API routes for file management."""

from typing import NoReturn

from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile
from fastapi.responses import FileResponse
from sqlmodel import Session

from agenteval.config import get_settings
from agenteval.services.files import (
    CategoryNotFoundError,
    FileManagementError,
    FileManagementService,
    FileRecordNotFoundError,
    FileValidationError,
    PhysicalFileNotFoundError,
    UploadTooLargeError,
)
from agenteval.storage.db import FILES_DIR
from agenteval.storage.file_storage import FileStorage
from agenteval.web.deps import get_db
from agenteval.web.file_schemas import (
    CategoryCreate,
    CategoryUpdate,
    FileCategoryResponse,
    FileRecordResponse,
    FileUploadConfigResponse,
    OkResponse,
)

router = APIRouter()


def _allowed_extensions() -> set[str]:
    raw = get_settings().allowed_extensions
    return {extension.strip().lower() for extension in raw.split(",") if extension.strip()}


def get_file_service(session: Session = Depends(get_db)) -> FileManagementService:
    settings = get_settings()
    return FileManagementService(
        session=session,
        storage=FileStorage(FILES_DIR),
        allowed_extensions=_allowed_extensions(),
        max_upload_size_mb=settings.max_upload_size_mb,
    )


def _raise_http_error(error: FileManagementError) -> NoReturn:
    if isinstance(error, UploadTooLargeError):
        raise HTTPException(
            status_code=413,
            detail=f"文件大小超过限制 ({get_settings().max_upload_size_mb}MB)",
        ) from error
    if isinstance(error, FileValidationError):
        raise HTTPException(status_code=400, detail=str(error)) from error
    if isinstance(error, CategoryNotFoundError):
        raise HTTPException(status_code=404, detail="分类不存在") from error
    if isinstance(error, FileRecordNotFoundError):
        raise HTTPException(status_code=404, detail="文件不存在") from error
    if isinstance(error, PhysicalFileNotFoundError):
        raise HTTPException(status_code=404, detail="物理文件不存在") from error
    raise HTTPException(status_code=500, detail="文件操作失败") from error


@router.get("/config", response_model=FileUploadConfigResponse)
def get_upload_config() -> FileUploadConfigResponse:
    return FileUploadConfigResponse(
        allowed_extensions=sorted(_allowed_extensions()),
        max_upload_size_mb=get_settings().max_upload_size_mb,
    )


@router.get("/categories", response_model=list[FileCategoryResponse])
def list_categories(service: FileManagementService = Depends(get_file_service)):
    return service.list_categories()


@router.post("/categories", response_model=FileCategoryResponse)
def create_category(body: CategoryCreate, service: FileManagementService = Depends(get_file_service)):
    try:
        return FileCategoryResponse.from_record(service.create_category(body.name, body.parent_id))
    except FileManagementError as error:
        _raise_http_error(error)


@router.put("/categories/{category_id}", response_model=FileCategoryResponse)
def update_category(
    category_id: str,
    body: CategoryUpdate,
    service: FileManagementService = Depends(get_file_service),
):
    try:
        return FileCategoryResponse.from_record(service.update_category(category_id, body.name))
    except FileManagementError as error:
        _raise_http_error(error)


@router.delete("/categories/{category_id}", response_model=OkResponse)
def delete_category(category_id: str, service: FileManagementService = Depends(get_file_service)):
    try:
        service.delete_category(category_id)
        return OkResponse()
    except FileManagementError as error:
        _raise_http_error(error)


@router.get("", response_model=list[FileRecordResponse])
def list_files(category_id: str | None = None, service: FileManagementService = Depends(get_file_service)):
    try:
        return [FileRecordResponse.from_record(record) for record in service.list_files(category_id)]
    except FileManagementError as error:
        _raise_http_error(error)


@router.post("/upload", response_model=FileRecordResponse)
async def upload_file(
    file: UploadFile = File(...),
    category_id: str | None = Form(default=None),
    service: FileManagementService = Depends(get_file_service),
):
    try:
        record = await service.upload(file, category_id)
        return FileRecordResponse.from_record(record)
    except FileManagementError as error:
        _raise_http_error(error)


@router.get("/{file_id}/download")
def download_file(file_id: str, service: FileManagementService = Depends(get_file_service)):
    try:
        record, file_path = service.get_download(file_id)
        return FileResponse(
            path=str(file_path),
            filename=record.original_name,
            media_type=record.mime_type or "application/octet-stream",
        )
    except FileManagementError as error:
        _raise_http_error(error)


@router.delete("/{file_id}", response_model=OkResponse)
def delete_file(file_id: str, service: FileManagementService = Depends(get_file_service)):
    try:
        service.delete_file(file_id)
        return OkResponse()
    except FileManagementError as error:
        _raise_http_error(error)
