from django.contrib.auth.models import Group, User
from rest_framework import mixins, status, viewsets
from rest_framework.authtoken.models import Token
from rest_framework.pagination import CursorPagination
from rest_framework.permissions import IsAdminUser, IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_hooks.models import Hook

from seed_scheduler.utils import get_available_metrics

from .models import Schedule, ScheduleFailure
from .serializers import (
    CreateUserSerializer,
    GroupSerializer,
    HookSerializer,
    ScheduleFailureSerializer,
    ScheduleSerializer,
    UserSerializer,
)
from .tasks import requeue_failed_tasks

# Uncomment line below if scheduled metrics are added
# from .tasks import scheduled_metrics


class CreatedAtCursorPagination(CursorPagination):
    ordering = "-created_at"


class IdCursorPagination(CursorPagination):
    ordering = "-id"


class HookViewSet(viewsets.ModelViewSet):
    """
    Retrieve, create, update or destroy webhooks.
    """

    permission_classes = (IsAuthenticated,)
    queryset = Hook.objects.all()
    serializer_class = HookSerializer
    pagination_class = IdCursorPagination

    def perform_create(self, serializer):
        serializer.save(user=self.request.user)


class UserViewSet(viewsets.ReadOnlyModelViewSet):

    """
    API endpoint that allows users to be viewed or edited.
    """

    permission_classes = (IsAuthenticated,)
    queryset = User.objects.all()
    serializer_class = UserSerializer
    pagination_class = IdCursorPagination


class GroupViewSet(viewsets.ReadOnlyModelViewSet):

    """
    API endpoint that allows groups to be viewed or edited.
    """

    permission_classes = (IsAuthenticated,)
    queryset = Group.objects.all()
    serializer_class = GroupSerializer
    pagination_class = IdCursorPagination


class UserView(APIView):
    """ API endpoint that allows users creation and returns their token.
    Only admin users can do this to avoid permissions escalation.
    """

    permission_classes = (IsAdminUser,)

    def post(self, request):
        """Create a user and token, given an email. If user exists just
        provide the token."""
        serializer = CreateUserSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        email = serializer.validated_data.get("email")
        try:
            user = User.objects.get(username=email)
        except User.DoesNotExist:
            user = User.objects.create_user(email, email=email)
        token, created = Token.objects.get_or_create(user=user)

        return Response(status=status.HTTP_201_CREATED, data={"token": token.key})


class ScheduleViewSet(viewsets.ModelViewSet):

    """
    API endpoint that allows schedule models to be viewed or edited.
    """

    permission_classes = (IsAuthenticated,)
    queryset = Schedule.objects.all()
    serializer_class = ScheduleSerializer
    pagination_class = CreatedAtCursorPagination

    def perform_create(self, serializer):
        serializer.save(created_by=self.request.user, updated_by=self.request.user)

    def perform_update(self, serializer):
        serializer.save(updated_by=self.request.user)


class MetricsView(APIView):

    """ Metrics Interaction
        GET - returns list of all available metrics on the service
        POST - starts up the task that fires all the scheduled metrics
    """

    permission_classes = (IsAuthenticated,)

    def get(self, request, *args, **kwargs):
        status = 200
        resp = {"metrics_available": get_available_metrics()}
        return Response(resp, status=status)

    def post(self, request, *args, **kwargs):
        status = 201
        # Uncomment line below if scheduled metrics are added
        # scheduled_metrics.apply_async()
        resp = {"scheduled_metrics_initiated": True}
        return Response(resp, status=status)


class HealthcheckView(APIView):

    """ Healthcheck Interaction
        GET - returns service up - getting auth'd requires DB
    """

    permission_classes = (IsAuthenticated,)

    def get(self, request, *args, **kwargs):
        import seed_scheduler
        import django
        import rest_framework

        status = 200
        resp = {
            "up": True,
            "result": {
                "database": "Accessible",
                "version": seed_scheduler.__version__,
                "libraries": {
                    "django": django.__version__,
                    "djangorestframework": rest_framework.__version__,
                },
            },
        }
        return Response(resp, status=status)


class FailedTaskViewSet(
    mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet
):
    permission_classes = (IsAuthenticated,)
    queryset = ScheduleFailure.objects.all()
    serializer_class = ScheduleFailureSerializer
    pagination_class = IdCursorPagination

    def create(self, request):
        status = 201
        resp = {"requeued_failed_tasks": True}
        requeue_failed_tasks.delay()
        return Response(resp, status=status)
