"""Token revocation endpoint"""
from dataclasses import dataclass

from django.http import Http404, HttpRequest, HttpResponse
from django.views import View
from structlog.stdlib import get_logger

from authentik.providers.oauth2.errors import TokenRevocationError
from authentik.providers.oauth2.models import OAuth2Provider, RefreshToken
from authentik.providers.oauth2.utils import TokenResponse, authenticate_provider

LOGGER = get_logger()


@dataclass
class TokenRevocationParams:
    """Parameters for Token Revocation"""

    token: RefreshToken
    provider: OAuth2Provider

    @staticmethod
    def from_request(request: HttpRequest) -> "TokenRevocationParams":
        """Extract required Parameters from HTTP Request"""
        raw_token = request.POST.get("token")
        token_type_hint = request.POST.get("token_type_hint", "access_token")
        token_filter = {token_type_hint: raw_token}

        if token_type_hint not in ["access_token", "refresh_token"]:
            LOGGER.debug("token_type_hint has invalid value", value=token_type_hint)
            raise TokenRevocationError("unsupported_token_type")

        provider = authenticate_provider(request)
        if not provider:
            raise TokenRevocationError("invalid_client")

        try:
            token: RefreshToken = RefreshToken.objects.get(provider=provider, **token_filter)
        except RefreshToken.DoesNotExist:
            LOGGER.debug("Token does not exist", token=raw_token)
            raise Http404

        return TokenRevocationParams(token=token, provider=provider)


class TokenRevokeView(View):
    """Token revoke endpoint
    https://datatracker.ietf.org/doc/html/rfc7009"""

    token: RefreshToken
    params: TokenRevocationParams
    provider: OAuth2Provider

    def post(self, request: HttpRequest) -> HttpResponse:
        """Revocation handler"""
        try:
            self.params = TokenRevocationParams.from_request(request)

            self.params.token.delete()

            return TokenResponse(data={}, status=200)
        except TokenRevocationError as exc:
            return TokenResponse(exc.create_dict(), status=401)
        except Http404:
            # Token not found should return a HTTP 200 according to the specs
            return TokenResponse(data={}, status=200)
