"""
A custom manager for calculating the total price of items in a shopping cart.

Additional managers for calculating the budget for a given project. It also includes
a custom queryset for filtering items based on the user's entity.

s. https://www.youtube.com/watch?v=n47VFgqG-E8&t=1463s
"""

from django.db import models
from django.db.models import Sum, F, FloatField
from django.db.models.functions import Coalesce


class BasketManager(models.Manager):
    """Custom manager for Basket model to calculate total price and budget."""

    def total_price(self, basket_id):
        """Calculate the total price of items in the basket."""
        return (
            self.filter(pk=basket_id)
            .annotate(total_price=Coalesce(Sum(F("items__quantity") * F("items__price"), output_field=FloatField()), 0))
            .values_list("total_price", flat=True)
            .first()
        )

    def budget_for_project(self, project_id):
        """Calculate the total budget for a given project."""
        return (
            self.filter(project_id=project_id)
            .annotate(
                total_budget=Coalesce(Sum(F("items__quantity") * F("items__price"), output_field=FloatField()), 0)
            )
            .values_list("total_budget", flat=True)
            .first()
        )


class ItemQuerySet(models.QuerySet):
    """Custom queryset for filtering items based on user's entity."""

    def for_user(self, user):
        """Filter items based on the user's entity."""
        return self.filter(basket__entity=user.entity)


class ItemManager(models.Manager):
    """Custom manager for Item model to use the custom queryset."""

    def get_queryset(self):
        """Return the custom queryset."""
        return ItemQuerySet(self.model, using=self._db)

    def for_user(self, user):
        """Filter items based on the user's entity."""
        return self.get_queryset().for_user(user)


class OrderItemManager(models.Manager):
    """Custom manager for OrderItem model to use the custom queryset."""

    def get_queryset(self):
        """Return the custom queryset."""
        return ItemQuerySet(self.model, using=self._db)

    def for_user(self, user):
        """Filter order items based on the user's entity."""
        return self.get_queryset().for_user(user)

    def total_price_for_user(self, user):
        """Calculate the total price of order items for a given user."""
        return (
            self.for_user(user)
            .annotate(total_price=Coalesce(Sum(F("quantity") * F("price"), output_field=FloatField()), 0))
            .values_list("total_price", flat=True)
            .first()
        )


class ProjectManager(models.Manager):
    """Custom manager for Project model to calculate total budget."""

    def total_budget_for_user(self, user):
        """Calculate the total budget for a given user's projects."""
        return (
            self.filter(entity=user.entity)
            .annotate(
                total_budget=Coalesce(
                    Sum(F("baskets__items__quantity") * F("baskets__items__price"), output_field=FloatField()), 0
                )
            )
            .values_list("total_budget", flat=True)
            .first()
        )
