from http import HTTPStatus
from typing import Callable

from fastapi import HTTPException, Request, Response
from fastapi.responses import JSONResponse
from fastapi.routing import APIRoute
from lnurl import LnurlErrorResponse, decode, encode, handle
from loguru import logger

from lnbits.exceptions import InvoiceError, PaymentError


class LnurlErrorResponseHandler(APIRoute):
    """
    Custom APIRoute class to handle LNURL errors.
    LNURL errors always return with status 200 and
    a JSON response with `status="ERROR"` and a `reason` key.
    Helps to catch HTTPException and return a valid lnurl error response

    Example:
    withdraw_lnurl_router = APIRouter(prefix="/api/v1/lnurl")
    withdraw_lnurl_router.route_class = LnurlErrorResponseHandler
    """

    def get_route_handler(self) -> Callable:
        original_route_handler = super().get_route_handler()

        async def lnurl_route_handler(request: Request) -> Response:
            try:
                response = await original_route_handler(request)
                return response
            except (InvoiceError, PaymentError) as exc:
                logger.debug(f"Wallet Error: {exc}")
                response = JSONResponse(
                    status_code=HTTPStatus.OK,
                    content={"status": "ERROR", "reason": f"{exc.message}"},
                )
                return response
            except HTTPException as exc:
                logger.debug(f"HTTPException: {exc}")
                response = JSONResponse(
                    status_code=HTTPStatus.OK,
                    content={"status": "ERROR", "reason": f"{exc.detail}"},
                )
                return response
            except Exception as exc:
                logger.error("Unknown Error:", exc)
                response = JSONResponse(
                    status_code=HTTPStatus.OK,
                    content={
                        "status": "ERROR",
                        "reason": f"UNKNOWN ERROR: {exc!s}",
                    },
                )
                return response

        return lnurl_route_handler


__all__ = [
    "decode",
    "encode",
    "handle",
    "LnurlErrorResponse",
    "LnurlErrorResponseHandler",
]
