# -*- encoding: utf-8 -*-

import json
import logging
import requests

from django.conf import settings
from django.db.utils import IntegrityError
from django.core.exceptions import ValidationError
from django_filters import rest_framework as rest_filters
from rest_framework import status, permissions, filters, generics
from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination
from rest_framework.authentication import SessionAuthentication, TokenAuthentication
from rest_framework.parsers import MultiPartParser, FormParser

from apps.home.models import Subscription, SavedGuilds
from apps.authentication.models import UserServerLink
from .serializers import (
    SubscriptionSerializer,
    UserServerLinkSerializer,
    SavedGuildSerializer
)

log = logging.getLogger(__name__)


class DefaultPagination(PageNumberPagination):
    """Default class for pagination in API views."""

    page_size = 10
    page_size_query_param = "page_size"
    max_page_size = 25


# =================================================================================================
# Subscription Views

class Subscription_ListView(generics.ListCreateAPIView):
    """
    View to provide a list of Subscription model instances.
    Can also be used to create a new instance.

    Supports: GET, POST
    """

    authentication_classes = [SessionAuthentication, TokenAuthentication]
    permission_classes = [permissions.IsAuthenticated]

    pagination_class = DefaultPagination
    serializer_class = SubscriptionSerializer
    queryset = Subscription.objects.all().order_by("-creation_datetime")

    filter_backends = [filters.SearchFilter, rest_filters.DjangoFilterBackend, filters.OrderingFilter]
    filterset_fields = ["id", "name", "url", "guild_id", "creation_datetime", "extra_notes", "active"]
    search_fields = ["name", "extra_notes"]
    ordering_fields = ["creation_datetime", "guild_id"]

    def post(self, request):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        try:
            self.perform_create(serializer)
        except IntegrityError as err:
            return Response(
                {"detail": str(err)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
                exception=True
            )

        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)


class Subscription_DetailView(generics.RetrieveUpdateDestroyAPIView):
    """
    View to provide details on a particular Subscription model instances.

    Supports: GET, PUT, PATCH, DELETE
    """

    authentication_classes = [SessionAuthentication, TokenAuthentication]
    permission_classes = [permissions.IsAuthenticated]
    parser_classes = [MultiPartParser, FormParser]

    serializer_class = SubscriptionSerializer
    queryset = Subscription.objects.all().order_by("-creation_datetime")

    # def get_queryset(self):
    #     user_servers = self.request.user.servers
    #     user_servers = [server.id for server in user_servers]
    #     return Subscription.objects \
    #         .filter(server__in=user_servers) \
    #         .order_by("-creation_datetime")


# =================================================================================================
# UserServerLinks Views

class UserServerLink_Pagination(PageNumberPagination):
    """
    Pagination for UserServerLink API views.
    Set to 200 as a discord user cannot exceed membership of
    200 discord servers.
    """

    page_size = 200
    page_size_query_param = "page_size"
    max_page_size = 200


class UserServerLink_MembershipPermission(permissions.BasePermission):
    """
    Permission for UserServerLink that requires the current user
    to be equal to the object.user.
    """

    def has_object_permission(self, request, view, obj):
        log.debug(f"{obj.name} {obj.user} {request.user}")
        return obj.user == request.user


class UserServerLink_ListView(generics.ListCreateAPIView):
    """
    View to provide a list of UserServerLink model instances.
    Can also be used to create a new instance.

    Supports: GET, POST
    """

    authentication_classes = [SessionAuthentication, TokenAuthentication]
    permission_classes = [permissions.IsAuthenticated, UserServerLink_MembershipPermission]

    pagination_class = UserServerLink_Pagination
    serializer_class = UserServerLinkSerializer

    filter_backends = [filters.SearchFilter, rest_filters.DjangoFilterBackend, filters.OrderingFilter]
    filterset_fields = ["id", "server_id", "user", "name", "permissions"]
    search_fields = ["name"]

    def get_queryset(self):
        return UserServerLink.objects.filter(user=self.request.user).order_by("id")

    def post(self, request):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        try:
            self.perform_create(serializer)
        except IntegrityError:
            return Response(
                {"detail": "UserServerLinks must be unique"},
                status=status.HTTP_409_CONFLICT,
                exception=True
            )

        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)


class UserServerLink_DetailView(generics.RetrieveDestroyAPIView):
    """
    View to provide details on a particular UserServerLink model instances.

    Supports: GET, DELETE
    """

    authentication_classes = [SessionAuthentication, TokenAuthentication]
    permission_classes = [permissions.IsAuthenticated, UserServerLink_MembershipPermission]
    parser_classes = [MultiPartParser, FormParser]

    serializer_class = UserServerLinkSerializer
    queryset = UserServerLink.objects.all()


# =================================================================================================
# SavedGuild Views

class SavedGuild_ListView(generics.ListCreateAPIView):
    """
    View to provide a list of SavedGuild model instances.
    Can also be used to create a new instance.

    Supports: GET, POST
    """

    authentication_classes = [SessionAuthentication, TokenAuthentication]
    permission_classes = [permissions.IsAuthenticated]

    pagination_class = None
    serializer_class = SavedGuildSerializer

    filter_backends = [filters.SearchFilter, rest_filters.DjangoFilterBackend, filters.OrderingFilter]
    filterset_fields = ["id", "guild_id", "name", "icon", "added_by", "permissions", "owner"]
    search_fields = ["name"]

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

    def post(self, request):
        
        is_owner = request.data["owner"].lower() == "true"

        # Check user is admin in server
        if not (self.is_server_admin(request.data["permissions"]) or is_owner):
            return Response(
                {"detail": "You must be a server administrator"},
                status=status.HTTP_403_FORBIDDEN,
                exception=False
            )

        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        try:
            self.perform_create(serializer)
        except IntegrityError as err:
            return Response(
                {"detail": str(err)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
                exception=True
            )

        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def is_server_admin(self, permissions) -> bool:

        return (int(permissions) & 1 << 3) == 1 << 3


class SavedGuild_DetailView(generics.RetrieveDestroyAPIView):
    """
    View to provide details on a particular UserServerLink model instances.

    Supports: GET, DELETE
    """

    authentication_classes = [SessionAuthentication, TokenAuthentication]
    permission_classes = [permissions.IsAuthenticated]
    parser_classes = [MultiPartParser, FormParser]

    serializer_class = SavedGuildSerializer

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