import logging
from typing import Any, Sequence, TYPE_CHECKING

from django.conf import settings
from django.forms import Select, SelectMultiple
from django.urls.exceptions import NoReverseMatch
from django.urls import reverse_lazy

from django_select2.forms import (
    Select2Mixin,
    HeavySelect2Mixin,
)
from .crispy_forms import Field

if TYPE_CHECKING:
    from django.forms import Widget

    LoggedInSelect2WidgetMixinBase = Widget
else:
    LoggedInSelect2WidgetMixinBase = object

logger = logging.getLogger(__name__)


# ------------------------------------------------------------------------
class LCSelect2Mixin(Select2Mixin):
    field_attrs: dict = {}
    if TYPE_CHECKING:
        is_required: bool

    def __init__(self, attrs: Any = None, choices: Sequence = (), **kwargs: Any) -> None:  # noqa
        super().__init__()

        field_attrs = kwargs.pop('field_attrs', None)
        if field_attrs:
            self.field_attrs = field_attrs

    def build_attrs(self, *args: Any, **kwargs: Any) -> dict:
        """Add select2 data attributes."""
        attrs = super().build_attrs(*args, **kwargs)

        if self.is_required:
            attrs.setdefault('data-allow-clear', 'false')
        else:
            attrs.setdefault('data-allow-clear', 'true')
            attrs.setdefault('data-placeholder', '')

        for k, v in self.field_attrs.items():
            attrs[k] = v
        self.field_attrs = {}

        attrs['data-minimum-input-length'] = 0
        if 'class' in attrs:
            attrs['class'] += ' django-select2'
        else:
            attrs['class'] = 'django-select2'
        return attrs


# ------------------------------------------------------------------------
class LCSelect2Widget(LCSelect2Mixin, Select):
    pass


# ------------------------------------------------------------------------
class LCSelect2MultipleWidget(LCSelect2Mixin, SelectMultiple):
    pass


# -------------------------------------------------------------------------
class LoggedInSelect2WidgetMixin(LoggedInSelect2WidgetMixinBase):
    """select2 widget to require login for JSON views"""

    field_attrs: dict = {}
    if TYPE_CHECKING:
        is_required: bool

    data_view = settings.FILTERED_DATA_VIEW_URL

    def __init__(self, *args: Any, **kwargs: Any) -> None:
        if 'data_view' not in kwargs:
            kwargs['data_view'] = self.data_view

        kwargs['attrs'] = dict(kwargs.get('attrs', {}))

        for k, v in self.field_attrs.items():
            if k not in kwargs['attrs']:
                kwargs['attrs'][k] = v

        super().__init__(*args, **kwargs)

    def build_attrs(self, *args: Any, **kwargs: Any) -> dict:
        attrs = super().build_attrs(*args, **kwargs)
        attrs.setdefault('data-ajax--delay', 175)
        return attrs


# -------------------------------------------------------------------------
class FilteredSelect2WidgetMixin(LoggedInSelect2WidgetMixin):
    """select2 widget to require login and
    company-filtered queryset for JSON views
    """

    search_fields: Sequence[str] = ()
    data_view = settings.FILTERED_DATA_VIEW_URL
    dependent_fields = settings.FILTERED_DEPENDENT_FIELDS

    def get_search_fields(self) -> list[str]:
        fields = list(self.search_fields)
        for field in self.dependent_fields:
            if field.startswith(settings.TENANT_FIELDS):
                fields.append(f'{field}__name__icontains')
        return fields


# ------------------------------------------------------------------------
class LCHeavySelect2Widget(HeavySelect2Mixin, LCSelect2Widget):
    pass


# ------------------------------------------------------------------------
class LCHeavySelect2MultipleWidget(HeavySelect2Mixin, LCSelect2MultipleWidget):
    pass


# ------------------------------------------------------------------------
class Select2Field(Field):
    """
    Field with settings defined for the "Add new..." URL
    when no entries are found.
    """

    create_url = ''
    prefill_field = 'name'

    def __init__(self, *args: Any, **kwargs: Any) -> None:
        new_url = kwargs.get('data_new_url', self.create_url)
        try:
            kwargs['data_new_url'] = reverse_lazy(new_url)
        except NoReverseMatch:
            pass
        if 'data_prefill_field' not in kwargs:
            kwargs['data_prefill_field'] = self.prefill_field
        super().__init__(*args, **kwargs)


__all__ = (
    'FilteredSelect2WidgetMixin',
    'LCHeavySelect2MultipleWidget',
    'LCHeavySelect2Widget',
    'LCSelect2Mixin',
    'LCSelect2Widget',
    'LCSelect2MultipleWidget',
    'LoggedInSelect2WidgetMixin',
    'Select2Field',
)
