from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from psycopg.errors import UniqueViolation
from sqlalchemy.exc import IntegrityError


class RenameError(Exception):
    """Error when renaming something"""

    def __init__(self, message: str = "Failed to rename source directory") -> None:
        super().__init__(message)


class MediaManagerError(Exception):
    """Base exception for MediaManager errors."""

    def __init__(self, message: str = "An error occurred.") -> None:
        super().__init__(message)
        self.message = message


class MediaAlreadyExistsError(MediaManagerError):
    """Raised when a media entity already exists (HTTP 409)."""

    def __init__(
        self, message: str = "Entity with this ID or other identifier already exists"
    ) -> None:
        super().__init__(message)


class NotFoundError(MediaManagerError):
    """Raised when an entity is not found (HTTP 404)."""

    def __init__(self, message: str = "The requested entity was not found.") -> None:
        super().__init__(message)


class InvalidConfigError(MediaManagerError):
    """Raised when the server is improperly configured (HTTP 500)."""

    def __init__(self, message: str = "The server is improperly configured.") -> None:
        super().__init__(message)


class BadRequestError(MediaManagerError):
    """Raised for invalid client requests (HTTP 400)."""

    def __init__(self, message: str = "Bad request.") -> None:
        super().__init__(message)


class UnauthorizedError(MediaManagerError):
    """Raised for authentication failures (HTTP 401)."""

    def __init__(self, message: str = "Unauthorized.") -> None:
        super().__init__(message)


class ForbiddenError(MediaManagerError):
    """Raised for forbidden actions (HTTP 403)."""

    def __init__(self, message: str = "Forbidden.") -> None:
        super().__init__(message)


class ConflictError(MediaManagerError):
    """Raised for resource conflicts (HTTP 409)."""

    def __init__(self, message: str = "Conflict.") -> None:
        super().__init__(message)


class UnprocessableEntityError(MediaManagerError):
    """Raised for validation errors (HTTP 422)."""

    def __init__(self, message: str = "Unprocessable entity.") -> None:
        super().__init__(message)


# Exception handlers
async def media_already_exists_exception_handler(
    _request: Request, _exc: Exception
) -> JSONResponse:
    return JSONResponse(status_code=409, content={"detail": str(_exc)})


async def not_found_error_exception_handler(
    _request: Request, _exc: Exception
) -> JSONResponse:
    return JSONResponse(status_code=404, content={"detail": str(_exc)})


async def invalid_config_error_exception_handler(
    _request: Request, _exc: Exception
) -> JSONResponse:
    return JSONResponse(status_code=500, content={"detail": str(_exc)})


async def bad_request_error_handler(
    _request: Request, exc: BadRequestError
) -> JSONResponse:
    return JSONResponse(status_code=400, content={"detail": exc.message})


async def unauthorized_error_handler(
    _request: Request, exc: UnauthorizedError
) -> JSONResponse:
    return JSONResponse(status_code=401, content={"detail": exc.message})


async def forbidden_error_handler(
    _request: Request, exc: ForbiddenError
) -> JSONResponse:
    return JSONResponse(status_code=403, content={"detail": exc.message})


async def conflict_error_handler(_request: Request, _exc: Exception) -> JSONResponse:
    return JSONResponse(status_code=409, content={"detail": str(_exc)})


async def unprocessable_entity_error_handler(
    _request: Request, exc: UnprocessableEntityError
) -> JSONResponse:
    return JSONResponse(status_code=422, content={"detail": exc.message})


async def sqlalchemy_integrity_error_handler(
    _request: Request, _exc: Exception
) -> JSONResponse:
    return JSONResponse(
        status_code=409,
        content={
            "detail": "The entity to create already exists or is in a conflict with others."
        },
    )


def register_exception_handlers(app: FastAPI) -> None:
    app.add_exception_handler(NotFoundError, not_found_error_exception_handler)
    app.add_exception_handler(
        MediaAlreadyExistsError, media_already_exists_exception_handler
    )
    app.add_exception_handler(
        InvalidConfigError, invalid_config_error_exception_handler
    )
    app.add_exception_handler(IntegrityError, sqlalchemy_integrity_error_handler)
    app.add_exception_handler(UniqueViolation, sqlalchemy_integrity_error_handler)
