# Generated by smithplates HTTP codegen. Do not edit.

from __future__ import annotations

import logging
import traceback
from typing import Protocol

from fastapi import Request
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from generated.smithplates.codegen.http.http_problem import HttpProblem
from generated.widget_api.widget_api.api_exceptions import NotImplementedApiError
from pydantic import BaseModel

LOGGER = logging.getLogger(__name__)


class FallbackApiExceptionHandler(Protocol):
    async def handle_not_implemented(
        self,
        request: Request,
        exc: NotImplementedApiError,
    ) -> JSONResponse: ...

    async def handle_validation_error(
        self,
        request: Request,
        exc: RequestValidationError,
    ) -> JSONResponse: ...

    async def handle_unexpected(
        self,
        request: Request,
        exc: Exception,
    ) -> JSONResponse: ...


def problem_json_response(status_code: int, problem: HttpProblem) -> JSONResponse:
    content = problem.model_dump(mode="json", exclude_none=True)
    content.setdefault("status", status_code)
    return JSONResponse(
        status_code=status_code,
        content=content,
        media_type="application/problem+json",
    )


def service_error_json_response(
    status_code: int,
    payload: BaseModel | None,
) -> JSONResponse:
    content = payload.model_dump(mode="json", exclude_none=True) if payload is not None else {}
    return JSONResponse(status_code=status_code, content=content)


class DefaultFallbackApiExceptionHandler:
    async def handle_not_implemented(
        self,
        request: Request,
        exc: NotImplementedApiError,
    ) -> JSONResponse:
        return problem_json_response(501, HttpProblem(title="Not implemented", status=501))

    async def handle_validation_error(
        self,
        request: Request,
        exc: RequestValidationError,
    ) -> JSONResponse:
        return problem_json_response(
            422,
            HttpProblem(
                title="Request validation failed",
                status=422,
                detail=str(exc.errors()),
            ),
        )

    async def handle_unexpected(
        self,
        request: Request,
        exc: Exception,
    ) -> JSONResponse:
        LOGGER.error(
            "Unhandled error for %s %s",
            request.method,
            request.url.path,
            exc_info=exc,
        )
        detail = traceback.format_exc()
        return problem_json_response(
            500,
            HttpProblem(
                title="Internal Server Error",
                status=500,
                detail=detail,
            ),
        )
