import re
from django.utils.regex_helper import _lazy_re_compile as re_compile
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.request import Request
from drf_spectacular.utils import extend_schema, extend_schema_view

from console_base.api.viewsets import LCModelViewSet
from console_base.http import FastJsonResponse

from encipher.models import EncryptionKey
from .filters import EncryptionKeyFilter
from .mixins import RecordSavedViaUmbrellaApi
from .serializers import EncryptionKeySerializer, EncryptionKeyDataTables, EncryptionKeyRevoke
from ..authentication import PasetoPinnedAuthentication

PASETO_KEY_ID = re_compile(r'^k[1-4].pid.', re.I)


# ---------------------------------------------------------------------------
@extend_schema_view(
    list=extend_schema(summary='List Encryption Keys'),
    retrieve=extend_schema(summary='Get a Encryption Key'),
    create=extend_schema(summary='Create a Encryption Key'),
    update=extend_schema(summary='Update a Encryption Key'),
    partial_update=extend_schema(summary='Partially Update a Encryption Key'),
    destroy=extend_schema(summary='Delete a Encryption Key'),
)
class EncryptionKeyViewSet(RecordSavedViaUmbrellaApi, LCModelViewSet):
    queryset = EncryptionKey.objects
    serializer_class = EncryptionKeySerializer
    datatables_serializer = EncryptionKeyDataTables
    filterset_class = EncryptionKeyFilter
    lookup_value_regex = '[^/]+'  # Capture UUIDs and Key IDs

    def get_object(self) -> EncryptionKey:
        """
        If the lookup value is a Paseto KeyID,
        change the lookup field to query by kid.
        """
        try:
            if PASETO_KEY_ID.match(self.kwargs['cid']) is not None:
                self.lookup_field = 'kid'
                self.kwargs['kid'] = self.kwargs['cid']
        except (KeyError, TypeError):
            pass
        return super().get_object()

    def get_authenticators(self):
        """
        Support auth verified by provided public key.
        """
        authenticators = super().get_authenticators()
        authenticators.insert(0, PasetoPinnedAuthentication())
        return authenticators

    @extend_schema(
        responses=EncryptionKeyRevoke,
        request=EncryptionKeyRevoke,
        summary='Revoke Encryption Key',
    )
    @action(detail=True, methods=['post', 'put'], name='Revoke Encryption Key')
    def revoke_encryption_key(self, request: Request, cid=None):
        """
        Revoke encryption key. Used when hardware is replaced,
        or temporary warm spares are provisioned.
        """
        key = self.get_object()
        serializer = EncryptionKeyRevoke(data=request.data, instance=key)
        if not serializer.is_valid():
            return FastJsonResponse(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

        serializer.save()
        return FastJsonResponse(serializer.validated_data, status=status.HTTP_200_OK)


__all__ = [
    'EncryptionKeyViewSet',
]
