from typing import Annotated, Self

from annotated_types import MinLen
from django.urls import reverse
from ninja import Field, FilterSchema, ModelSchema, Schema
from pydantic import model_validator

from club.schemas import ClubSchema
from core.schemas import GroupSchema, SimpleUserSchema
from counter.models import Counter, Product, ProductType


class CounterSchema(ModelSchema):
    barmen_list: list[SimpleUserSchema]
    is_open: bool

    class Meta:
        model = Counter
        fields = ["id", "name", "type", "club", "products"]


class CounterFilterSchema(FilterSchema):
    search: Annotated[str, MinLen(1)] = Field(None, q="name__icontains")


class SimplifiedCounterSchema(ModelSchema):
    class Meta:
        model = Counter
        fields = ["id", "name"]


class ProductTypeSchema(ModelSchema):
    class Meta:
        model = ProductType
        fields = ["id", "name", "description", "comment", "icon", "order"]

    url: str

    @staticmethod
    def resolve_url(obj: ProductType) -> str:
        return reverse("counter:product_type_edit", kwargs={"type_id": obj.id})


class SimpleProductTypeSchema(ModelSchema):
    class Meta:
        model = ProductType
        fields = ["id", "name"]


class ReorderProductTypeSchema(Schema):
    below: int | None = None
    above: int | None = None

    @model_validator(mode="after")
    def validate_exclusive(self) -> Self:
        if self.below is None and self.above is None:
            raise ValueError("Either 'below' or 'above' must be set.")
        if self.below is not None and self.above is not None:
            raise ValueError("Only one of 'below' or 'above' must be set.")
        return self


class SimpleProductSchema(ModelSchema):
    class Meta:
        model = Product
        fields = ["id", "name", "code"]


class ProductSchema(ModelSchema):
    class Meta:
        model = Product
        fields = [
            "id",
            "name",
            "code",
            "description",
            "purchase_price",
            "selling_price",
            "icon",
            "limit_age",
            "archived",
        ]

    buying_groups: list[GroupSchema]
    club: ClubSchema
    product_type: SimpleProductTypeSchema | None
    url: str

    @staticmethod
    def resolve_url(obj: Product) -> str:
        return reverse("counter:product_edit", kwargs={"product_id": obj.id})


class ProductFilterSchema(FilterSchema):
    search: Annotated[str, MinLen(1)] | None = Field(
        None, q=["name__icontains", "code__icontains"]
    )
    is_archived: bool | None = Field(None, q="archived")
    buying_groups: set[int] | None = Field(None, q="buying_groups__in")
    product_type: set[int] | None = Field(None, q="product_type__in")