from django import forms
from django.db.models import Model
from django.utils.functional import cached_property

from wagtail import blocks
from wagtail.admin.telepath import register

from ocyan.plugin.coyote.definitions import get_coyote_definitions
from ocyan.plugin.coyote.utils import LinkPageString, LocalizedLinkPage

from .adapters import (
    AdminLinkChooserAdapter,
    ColorChoiceAdapter,
    IconChoiceAdapter,
    VisualChoiceAdapter,
)
from .fields import LinkModelChoiceField
from .widgets import AdminLinkChooser, ColorSelect, IconSelect, VisualSelect


class ColorChoiceBlock(blocks.ChoiceBlock):
    def __init__(self, *args, **kwargs):
        kwargs["required"] = False
        super().__init__(*args, **kwargs)

    def choices(self):
        definitions = get_coyote_definitions()
        return [
            ("background_body", definitions["body-background"]),
            ("dark", definitions["gray-900"]),
            ("light", definitions["gray-200"]),
        ]

    def get_field(self, **kwargs):
        kwargs["widget"] = ColorSelect
        return forms.ChoiceField(**kwargs)

    class Meta:
        admin_text = ""
        label = " "


class VisualChoiceBlock(blocks.ChoiceBlock):
    def get_field(self, **kwargs):
        kwargs["widget"] = VisualSelect
        return forms.ChoiceField(**kwargs)


class IconChoiceBlock(blocks.ChoiceBlock):
    def get_field(self, **kwargs):
        kwargs["widget"] = IconSelect
        return forms.ChoiceField(**kwargs)


class LinkChooserBlock(blocks.PageChooserBlock):
    @cached_property
    def field(self):
        return LinkModelChoiceField(
            queryset=self.target_model.objects.all(),
            widget=self.widget,
            required=self._required,
            validators=self._validators,
            help_text=self._help_text,
        )

    @cached_property
    def widget(self):
        return AdminLinkChooser(
            target_models=self.target_models, can_choose_root=self.can_choose_root
        )

    def value_from_form(self, value):
        if isinstance(value, str):
            return value

        return super().value_from_form(value)

    def get_prep_value(self, value):
        if isinstance(value, LocalizedLinkPage):
            return value.pk

        if isinstance(value, self.target_model):
            return value.pk

        return value

    def to_python(self, value):
        value = super().to_python(value)
        if isinstance(value, self.target_model):
            return LocalizedLinkPage(value)
        if isinstance(value, str):
            return LinkPageString(value)
        return value

    def bulk_to_python(self, values):
        ids = filter(lambda x: isinstance(x, int), values)
        objects = self.target_model.objects.in_bulk(ids)

        def to_usable_value(_value):
            value = objects.get(_value, _value)

            if isinstance(value, str):
                return LinkPageString(value)
            if isinstance(value, self.target_model):
                return LocalizedLinkPage(value)

            return value

        return list(map(to_usable_value, values))

    def extract_references(self, value):
        if isinstance(value, LocalizedLinkPage):
            value = value.page

        if (
            value is not None
            and issubclass(self.model_class, Model)
            and isinstance(value, Model)
        ):
            yield self.model_class, str(value.pk), "", ""


register(ColorChoiceAdapter(), ColorSelect)
register(VisualChoiceAdapter(), VisualSelect)
register(IconChoiceAdapter(), IconSelect)
register(AdminLinkChooserAdapter(), AdminLinkChooser)
