from typing import Annotated, Any, Literal
from urllib.parse import quote

from fastapi import APIRouter, Depends, File, Form, Request, UploadFile, status
from fastapi.responses import Response
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from pydantic import BaseModel, Field

from zbt.api.responses import success_response
from zbt.core.errors import AppError
from zbt.domains.identity.models import AdminUser, H5User
from zbt.domains.identity.service import AdminAuthService, H5AuthService
from zbt.domains.service_request.service import ServiceRequestService

service_bearer = HTTPBearer(auto_error=False)


class SubmitServiceRequest(BaseModel):
    policy_id: str = Field(min_length=26, max_length=26)
    request_type: Literal["MEDICAL_REIMBURSEMENT_ASSISTANCE"]
    recognition_id: str = Field(min_length=26, max_length=26)
    confirmed_fields: dict[str, str]


class ReviewServiceRequest(BaseModel):
    decision: Literal["ACCEPTED", "REJECTED"]


def create_service_request_router(
    service: ServiceRequestService,
    h5_auth_service: H5AuthService,
    admin_auth_service: AdminAuthService,
) -> APIRouter:
    router = APIRouter(tags=["service-requests"])

    def current_h5_user(
        credentials: Annotated[
            HTTPAuthorizationCredentials | None,
            Depends(service_bearer),
        ],
    ) -> H5User:
        if credentials is None:
            raise AppError("AUTH_REQUIRED", "请先登录", 401)
        return h5_auth_service.authenticate_access(credentials.credentials)

    def current_admin(
        credentials: Annotated[
            HTTPAuthorizationCredentials | None,
            Depends(service_bearer),
        ],
    ) -> AdminUser:
        if credentials is None:
            raise AppError("AUTH_REQUIRED", "请先登录后台", 401)
        return admin_auth_service.authenticate_access(credentials.credentials)

    def require_permission(user: AdminUser, permission: str) -> None:
        if "*" not in user.permissions and permission not in user.permissions:
            raise AppError("PERMISSION_DENIED", "当前角色无权处理服务申请", 403)

    @router.post(
        "/h5/service-materials/recognize",
        status_code=status.HTTP_201_CREATED,
    )
    async def recognize_material(
        request: Request,
        user: Annotated[H5User, Depends(current_h5_user)],
        file: Annotated[UploadFile, File()],
        policy_id: Annotated[str, Form(min_length=26, max_length=26)],
        material_type: Annotated[
            Literal["MEDICAL_INVOICE", "EXPENSE_LIST", "DIAGNOSIS_CERTIFICATE"],
            Form(),
        ],
    ) -> dict[str, Any]:
        content = await file.read()
        if len(content) > 10 * 1024 * 1024:
            raise AppError("MATERIAL_TOO_LARGE", "单张材料不能超过10MB", 413)
        return success_response(
            request,
            service.recognize_material(
                user,
                policy_id=policy_id,
                material_type=material_type,
                source_name=file.filename or "service-material",
                media_type=file.content_type or "application/octet-stream",
                content=content,
            ),
        )

    @router.post("/h5/service-requests", status_code=status.HTTP_201_CREATED)
    def submit_request(
        payload: SubmitServiceRequest,
        request: Request,
        user: Annotated[H5User, Depends(current_h5_user)],
    ) -> dict[str, Any]:
        return success_response(
            request,
            service.submit_request(
                user,
                policy_id=payload.policy_id,
                request_type=payload.request_type,
                recognition_id=payload.recognition_id,
                confirmed_fields=payload.confirmed_fields,
            ),
        )

    @router.get("/h5/service-requests")
    def list_user_requests(
        request: Request,
        user: Annotated[H5User, Depends(current_h5_user)],
    ) -> dict[str, Any]:
        return success_response(request, service.list_user_requests(user))

    @router.get("/admin/service-requests")
    def list_admin_requests(
        request: Request,
        user: Annotated[AdminUser, Depends(current_admin)],
    ) -> dict[str, Any]:
        require_permission(user, "service:read")
        return success_response(request, service.list_all_requests())

    @router.get("/admin/service-requests/{request_id}/material")
    def get_admin_request_material(
        request_id: str,
        user: Annotated[AdminUser, Depends(current_admin)],
    ) -> Response:
        require_permission(user, "service:read")
        material, media_type, source_name = service.get_request_material(request_id)
        encoded_name = quote(source_name, safe="")
        return Response(
            content=material.content,
            media_type=media_type,
            headers={
                "Content-Disposition": f"inline; filename*=UTF-8''{encoded_name}",
                "Cache-Control": "private, max-age=300",
            },
        )

    @router.post("/admin/service-requests/{request_id}/review")
    def review_request(
        request_id: str,
        payload: ReviewServiceRequest,
        request: Request,
        user: Annotated[AdminUser, Depends(current_admin)],
    ) -> dict[str, Any]:
        require_permission(user, "service:review")
        return success_response(
            request,
            service.review_request(
                request_id,
                decision=payload.decision,
                reviewer_id=user.id,
            ),
        )

    return router
