from collections.abc import Collection
from typing import Any

from django.contrib.staticfiles.storage import staticfiles_storage
from django.db.models import Model, QuerySet
from django.forms import Select, SelectMultiple
from ninja import ModelSchema
from pydantic import TypeAdapter

from core.models import Group, SithFile, User
from core.schemas import GroupSchema, SithFileSchema, UserProfileSchema


class AutoCompleteSelectMixin:
    component_name = "autocomplete-select"
    template_name = "core/widgets/autocomplete_select.jinja"
    model: type[Model] | None = None
    adapter: TypeAdapter[Collection[ModelSchema]] | None = None
    pk = "id"

    js = [
        "bundled/core/components/ajax-select-index.ts",
    ]
    css = [
        "bundled/core/components/ajax-select-index.css",
        "core/components/ajax-select.scss",
    ]

    def get_queryset(self, pks: Collection[Any]) -> QuerySet:
        return self.model.objects.filter(
            **{
                f"{self.pk}__in": [
                    pk
                    for pk in pks
                    if str(pk).isdigit()  # We filter empty values for create views
                ]
            }
        ).all()

    def __init__(self, attrs=None, choices=()):
        if self.is_ajax:
            choices = ()  # Avoid computing anything when in ajax mode
        super().__init__(attrs=attrs, choices=choices)

    @property
    def is_ajax(self):
        return self.adapter and self.model

    def optgroups(self, name, value, attrs=None):
        """Don't create option groups when doing ajax"""
        if self.is_ajax:
            return []
        return super().optgroups(name, value, attrs=attrs)

    def get_context(self, name, value, attrs):
        context = super().get_context(name, value, attrs)
        context["widget"]["attrs"]["autocomplete"] = "off"
        context["component"] = self.component_name
        context["statics"] = {
            "js": [staticfiles_storage.url(file) for file in self.js],
            "css": [staticfiles_storage.url(file) for file in self.css],
        }
        if self.is_ajax:
            context["initial"] = self.adapter.dump_json(
                self.adapter.validate_python(
                    self.get_queryset(context["widget"]["value"])
                )
            ).decode("utf-8")
        return context


class AutoCompleteSelect(AutoCompleteSelectMixin, Select): ...


class AutoCompleteSelectMultiple(AutoCompleteSelectMixin, SelectMultiple): ...


class AutoCompleteSelectUser(AutoCompleteSelect):
    component_name = "user-ajax-select"
    model = User
    adapter = TypeAdapter(list[UserProfileSchema])


class AutoCompleteSelectMultipleUser(AutoCompleteSelectMultiple):
    component_name = "user-ajax-select"
    model = User
    adapter = TypeAdapter(list[UserProfileSchema])


class AutoCompleteSelectGroup(AutoCompleteSelect):
    component_name = "group-ajax-select"
    model = Group
    adapter = TypeAdapter(list[GroupSchema])


class AutoCompleteSelectMultipleGroup(AutoCompleteSelectMultiple):
    component_name = "group-ajax-select"
    model = Group
    adapter = TypeAdapter(list[GroupSchema])


class AutoCompleteSelectSithFile(AutoCompleteSelect):
    component_name = "sith-file-ajax-select"
    model = SithFile
    adapter = TypeAdapter(list[SithFileSchema])


class AutoCompleteSelectMultipleSithFile(AutoCompleteSelectMultiple):
    component_name = "sith-file-ajax-select"
    model = SithFile
    adapter = TypeAdapter(list[SithFileSchema])