from itertools import groupby

from django.db.models import F, Func, Sum, Value
from django.db.models.functions import Concat, TruncDay, TruncMonth, TruncYear
from rest_framework.response import Response
from rest_framework.views import APIView

from core.apps.eggs.models import Order
from core.http.permissions import IsRole


class WeekOfMonth(Func):
    function = "EXTRACT"
    template = "(%(function)s('day' from %(expressions)s) - 1) / 7 + 1"

    def as_postgresql(self, compiler, connection):
        self.template = (
            "ROUND((EXTRACT('day' from %(expressions)s) - 1) / 7 + 1)"
        )
        return super().as_sql(compiler, connection)


class DayName(Func):
    function = "to_char"
    template = "%(function)s(%(expressions)s, 'Day')"


class TopCourierView(APIView):
    permission_classes = [IsRole(["admin"])]

    def get(self, request):
        top_couriers = (
            Order.objects.annotate(
                year=TruncYear("created_at"),
                month=TruncMonth("created_at"),
                day=TruncDay("created_at"),
                day_name=DayName("created_at"),
                full_name=Concat(
                    F("courier_id__user_id__first_name"),
                    Value(" "),
                    F("courier_id__user_id__last_name"),
                ),
            )
            .values(
                "year",
                "month",
                "day",
                "day_name",
                "full_name",
            )
            .annotate(value=Sum("order_items__count"))
            .order_by("year", "month", "day", "-value")
        )[:3]

        data = []
        for year, year_data in groupby(top_couriers, key=lambda x: x["year"]):
            year_dict = {"Year": year.year, "Months": []}
            for month, month_data in groupby(
                year_data, key=lambda x: x["month"]
            ):
                month_dict = {"month": month.strftime("%B"), "days": []}
                for day, day_data in groupby(
                    month_data, key=lambda x: x["day"]
                ):
                    day_data_list = list(day_data)
                    people_list = [
                        {
                            "full_name": person["full_name"],
                            "value": person["value"],
                        }
                        for person in day_data_list
                    ]
                    day_dict = {
                        "day": day.day,
                        "day_name": day_data_list[0]["day_name"].strip(),
                        "people": people_list,
                    }
                    month_dict["days"].append(day_dict)
                year_dict["Months"].append(month_dict)
            data.append(year_dict)
        return Response(data)
