from fastapi import HTTPException, FastAPI
from fastapi.exceptions import RequestValidationError
from starlette.responses import JSONResponse
from starlette.exceptions import HTTPException as StarletteHTTPException

from tonilib.fastapi.exception.validation_converter import convert_validation_errors, ValidationConvertedError
from tonilib.fastapi.models import Failure, ApiResponse


async def http_exception_handler(request, exc: HTTPException):
    failure = Failure(title="HttpException", msg=str(exc.detail)).failure_data
    return JSONResponse(ApiResponse(error=failure).model_dump(), status_code=exc.status_code)


async def http_starlette_exception_handler(request, exc: StarletteHTTPException):
    failure = Failure(title="HttpException", msg=str(exc.detail)).failure_data
    return JSONResponse(ApiResponse(error=failure).model_dump(), status_code=exc.status_code)


async def validation_exception_handler(request, exc: RequestValidationError):
    errs = convert_validation_errors(exc)
    err = errs[0] if errs else ValidationConvertedError(type="validation_error", loc="", msg=str(exc))
    failure = Failure(title=err.type, msg=err.loc).failure_data
    return JSONResponse(ApiResponse(error=failure).model_dump(), status_code=400)


async def generic_exception_handler(request, exc: Exception):
    failure = Failure(title="Error", msg=str(exc)).failure_data
    return JSONResponse(ApiResponse(error=failure).model_dump(), status_code=500)


async def failure_exception_handler(request, exc: Failure):
    return JSONResponse(ApiResponse(error=exc.failure_data).model_dump(), status_code=500)


def setup_tonilib_exception_handler(app: FastAPI) -> None:
    app.add_exception_handler(HTTPException, http_exception_handler)
    app.add_exception_handler(StarletteHTTPException, http_starlette_exception_handler)
    app.add_exception_handler(RequestValidationError, validation_exception_handler)
    app.add_exception_handler(Exception, generic_exception_handler)
    app.add_exception_handler(Failure, failure_exception_handler)
