import logging
from datetime import datetime, timezone

from fastapi import Request
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from starlette.exceptions import HTTPException as StarletteHTTPException

logger = logging.getLogger(__name__)


class GuestErrorCode:
    GUEST_SESSION_NOT_FOUND = "GUEST_SESSION_NOT_FOUND"
    GUEST_SESSION_INVALID = "GUEST_SESSION_INVALID"
    GUEST_SESSION_MERGED = "GUEST_SESSION_MERGED"
    GUEST_ACCESS_DENIED = "GUEST_ACCESS_DENIED"
    GUEST_MERGE_CONFLICT = "GUEST_MERGE_CONFLICT"
    GUEST_MERGE_IDEMPOTENT_REPLAY = "GUEST_MERGE_IDEMPOTENT_REPLAY"
    IDEMPOTENCY_KEY_REQUIRED = "IDEMPOTENCY_KEY_REQUIRED"

_STATUS_LABELS = {
    400: "Bad Request",
    401: "Unauthorized",
    403: "Forbidden",
    404: "Not Found",
    409: "Conflict",
    422: "Unprocessable Entity",
    429: "Too Many Requests",
    500: "Internal Server Error",
    503: "Service Unavailable",
}


def _ts() -> str:
    return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")


async def http_exception_handler(request: Request, exc: StarletteHTTPException) -> JSONResponse:
    detail = exc.detail if isinstance(exc.detail, str) else str(exc.detail)
    return JSONResponse(
        status_code=exc.status_code,
        content={
            "error": _STATUS_LABELS.get(exc.status_code, "Error"),
            "message": detail,
            "statusCode": exc.status_code,
            "timestamp": _ts(),
            "path": str(request.url.path),
        },
    )


async def validation_exception_handler(
    request: Request, exc: RequestValidationError
) -> JSONResponse:
    messages = [
        f"{'.'.join(str(loc) for loc in e['loc'])}: {e['msg']}" for e in exc.errors()
    ]
    return JSONResponse(
        status_code=422,
        content={
            "error": "Unprocessable Entity",
            "message": "; ".join(messages),
            "statusCode": 422,
            "timestamp": _ts(),
            "path": str(request.url.path),
        },
    )


async def generic_exception_handler(request: Request, exc: Exception) -> JSONResponse:
    logger.exception("Unhandled exception on %s: %s", request.url.path, exc)
    return JSONResponse(
        status_code=500,
        content={
            "error": "Internal Server Error",
            "message": "Une erreur inattendue s'est produite",
            "statusCode": 500,
            "timestamp": _ts(),
            "path": str(request.url.path),
        },
    )
