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

import logging
from typing import Any

from django.db.models import Q
from django.http import HttpRequest
from django.core.cache import cache
from django.views.decorators.cache import cache_page
from django.utils.decorators import method_decorator
from django.core.exceptions import ValidationError
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status, permissions
from rest_framework.pagination import PageNumberPagination

from apps.home.models import Ticket, TicketPriority, TicketTag
from apps.authentication.models import Department
from .serializers import (
    TicketSerializer, TicketTagSerializer, TicketPrioritySerializer,
    UserSerializer
)

log = logging.getLogger(__name__)

def respond_error(error: Exception, status: Any) -> Response:
    logging.error(error)
    return Response({
        "detail": str(error),
        "error": error.__class__.__name__
    }, status=status)


class TicketPaginiation(PageNumberPagination):
    page_size = 25
    page_size_query_param = "page_size"
    max_page_size = 100


class TicketListApiView(APIView):
    permission_classes = [permissions.IsAuthenticated]
    pagination_class = TicketPaginiation

    ALLOWED_FILTERS = ("uuid__in", "priority__in", "tags__in", "author__department__in")

    # @method_decorator(cache_page(60 * 5))
    def get(self, request: HttpRequest) -> Response:
        """Returns a response containing tickets matching the given filters."""

        try:
            return self._get_tickets(request)

        except KeyError as error:
            return respond_error(error, status.HTTP_400_BAD_REQUEST)

        except ValidationError as error:
            return respond_error(error, status.HTTP_400_BAD_REQUEST)

    def post(self, request):
        """Create a new ticket"""

        serializer = TicketSerializer(data={

        })
        if not serializer.is_valid():
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

        serializer.save()
        return Response(serializer.data, status=status.HTTP_201_CREATED)


    def _get_tickets(self, request: HttpRequest) -> Response:
        """Returns a response containing tickets matching the given filters.

        Parameters
        ----------
        request : HttpRequest
            The request containing the filters.

        Returns
        -------
        Response
            A response containing the tickets data.

        Raises
        ------
        KeyError
            If any given filter key isn't in `self.ALLOWED_FILTERS`.
        ValidationError
            If any ValidationErrors are raised by Django while applying filters.
        """

        queryset = Ticket.objects.all()

        for key in request.GET.keys():
            values = request.GET.getlist(key) if key.endswith("[]") else [request.GET.get(key)]
            key = key.removesuffix("[]")

            if key not in self.ALLOWED_FILTERS:
                raise KeyError(key)

            for value in values:
                if value == "all": continue
                queryset = queryset.filter(Q(**{key: [value]}))

        tickets = queryset.order_by("-create_timestamp")
        serializer = TicketSerializer(tickets, many=True)
        response_data = serializer.data

        log.debug("Query successful showing %s results", tickets.count())
        return Response(response_data, status=status.HTTP_200_OK)


class FilterCountApiView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    @method_decorator(cache_page(60 * 5))
    def get(self, request):

        priorities = TicketPriority.objects.all()
        tags = TicketTag.objects.all()
        departments = Department.objects.all()

        tickets = Ticket.objects.all()

        data = {
            "priority_counts": {},
            "tag_counts": {},
            "department_counts": {},
            "ticket_count": tickets.count()
        }

        for priority in priorities:
            data["priority_counts"][str(priority.uuid)] = tickets.filter(priority=priority).count()

        for tag in tags:
            data["tag_counts"][str(tag.uuid)] = tickets.filter(tags__in=[tag]).count()

        for department in departments:
            data["department_counts"][str(department.uuid)] = tickets.filter(author__department=department).count()

        return Response(data, status=status.HTTP_200_OK)