import typing

from sqlalchemy.sql import desc, func

from models import Location, Order, OrderItem, Product, User


class FatModel:
    @classmethod
    def all(cls):
        return cls.query.all()

    @classmethod
    def amount(cls):
        return cls.query.count()


class FatLocation(Location, FatModel):
    pass


class FatOrder(Order, FatModel):

    # It's hard to add the unique user constraint,
    #  as DISTINCT seems to apply after a GROUP BY and aggregate
    # So DISTINCT ... count(user_id) ... will count all users,
    #  even if they get reduced by the disctinct afterwards.
    @classmethod
    def items_per_order(cls):
        return (
            Order.query.join(OrderItem).group_by(Order.id)
            .with_entities(Order.id,
                           func.count(OrderItem.user_id).label("total"))
        )


class FatUser(User, FatModel):
    pass


class FatOrderItem(OrderItem, FatModel):
    pass


class FatProduct(Product, FatModel):
    @classmethod
    def top4(cls) -> None:
        top4 = (
            OrderItem.query.join(Product)
            .join(Location)
            .group_by(Product.id)
            .with_entities(
                Product.name, Location.name, func.count(
                    Product.id).label("count")
            )
            .order_by(desc("count"))
            .limit(4)
        )
        for top in top4:
            print(top)
