import random
import string
from logging import getLogger

from django.core.cache import cache
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page
from django_redis import get_redis_connection
from rest_framework import generics, status
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

from common.auth import JWTAuth
from common.serializers import ProductSerializer, LinkSerializer
from core.models import Product, Link

logger = getLogger(__name__)


class ProductFrontendView(generics.ListAPIView):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
    ordering = ('id',)  # default order

    @method_decorator(cache_page(15 * 60, key_prefix='products_frontend'))
    def get(self, request, *args, **kwargs):
        return super().get(request, *args, *kwargs)


class ProductBackendView(generics.ListAPIView):
    # queryset = Product.objects.all()  # overridden with get_queryset()
    serializer_class = ProductSerializer
    search_fields = ('title', 'description')
    ordering_fields = ('id', 'title', 'price')
    ordering = ('id', )  # default order

    def get_queryset(self):
        """Overridden to include redis caching"""
        qs = cache.get('products_backend')

        if not qs:  # no cache found
            qs = Product.objects.all()
            cache.set('products_backend', qs, timeout=15 * 60)  # 15 mins TTL

        return qs


class LinkCreateListView(generics.ListCreateAPIView):
    queryset = Link.objects.all()
    serializer_class = LinkSerializer
    ordering = ('id', )

    def create(self, request, *args, **kwargs):
        # add the user and code
        request.data.update({
            'user': request.user.id,
            'code': ''.join(random.choices(string.ascii_lowercase + string.digits, k=6))
        })

        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def list(self, request, *args, **kwargs):
        return super().list(request, *args, **kwargs)

    def get_queryset(self):
        return Link.objects.filter(user=self.request.user)


class RankingsAPIView(APIView):
    authentication_classes = [JWTAuth]
    permission_classes = [IsAuthenticated]

    def get(self, _):
        conn = get_redis_connection('default')

        # https://redis.io/commands/zrevrangebyscore
        rankings = conn.zrevrangebyscore('rankings', min=0, max=1000, withscores=True)

        rankings = {rank[0].decode('utf-8'): rank[1] for rank in rankings}

        return Response(rankings)

import random
import string
from logging import getLogger

from django.core.cache import cache
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page
from django_redis import get_redis_connection
from rest_framework import generics, status
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

from common.auth import JWTAuth
from common.serializers import ProductSerializer, LinkSerializer
from core.models import Product, Link

logger = getLogger(__name__)


class ProductFrontendView(generics.ListAPIView):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
    ordering = ('id',)  # default order

    @method_decorator(cache_page(15 * 60, key_prefix='products_frontend'))
    def get(self, request, *args, **kwargs):
        return super().get(request, *args, *kwargs)


class ProductBackendView(generics.ListAPIView):
    # queryset = Product.objects.all()  # overridden with get_queryset()
    serializer_class = ProductSerializer
    search_fields = ('title', 'description')
    ordering_fields = ('id', 'title', 'price')
    ordering = ('id', )  # default order

    def get_queryset(self):
        """Overridden to include redis caching"""
        qs = cache.get('products_backend')

        if not qs:  # no cache found
            qs = Product.objects.all()
            cache.set('products_backend', qs, timeout=15 * 60)  # 15 mins TTL

        return qs


class LinkCreateListView(generics.ListCreateAPIView):
    queryset = Link.objects.all()
    serializer_class = LinkSerializer
    ordering = ('id', )

    def create(self, request, *args, **kwargs):
        # add the user and code
        request.data.update({
            'user': request.user.id,
            'code': ''.join(random.choices(string.ascii_lowercase + string.digits, k=6))
        })

        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def list(self, request, *args, **kwargs):
        return super().list(request, *args, **kwargs)

    def get_queryset(self):
        return Link.objects.filter(user=self.request.user)


class RankingsAPIView(APIView):
    authentication_classes = [JWTAuth]
    permission_classes = [IsAuthenticated]

    def get(self, _):
        conn = get_redis_connection('default')

        # https://redis.io/commands/zrevrangebyscore
        rankings = conn.zrevrangebyscore('rankings', min=0, max=1000, withscores=True)

        rankings = {rank[0].decode('utf-8'): rank[1] for rank in rankings}

        return Response(rankings)

# default order # queryset = Product.objects.all()  # overridden with get_queryset() # default order Overridden to include redis caching # no cache found # 15 mins TTL # add the user and code # https://redis.io/commands/zrevrangebyscore