import re

from django import forms
from django.db.models import Max
from django.utils import timezone
from django.utils.encoding import smart_str
from django.utils.translation import gettext_lazy as _

from ..models import Category


class CategoryForm(forms.ModelForm):
    class Meta:
        model = Category
        fields = (
            "parent",
            "title",
            "description",
            "is_global",
            "is_closed",
            "is_removed",
            "color",
        )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        queryset = Category.objects.visible().parents().ordered()

        if self.instance.pk:
            queryset = queryset.exclude(pk=self.instance.pk)

        self.fields["parent"] = forms.ModelChoiceField(
            queryset=queryset, required=False
        )
        self.fields["parent"].label_from_instance = lambda obj: smart_str(obj.title)

    def clean_parent(self):
        parent = self.cleaned_data["parent"]

        if self.instance.pk:
            has_children = self.instance.category_set.all().exists()

            if parent and has_children:
                raise forms.ValidationError(
                    _(
                        "The category you are updating can not have a parent since it has childrens"
                    )
                )

        return parent

    def clean_color(self):
        color = self.cleaned_data["color"]

        if color and not re.match(r"^#([A-Fa-f0-9]{3}){1,2}$", color):
            raise forms.ValidationError(_("The input is not a valid hex color."))

        return color

    def get_max_sort(self):
        return Category.objects.aggregate(max_sort=Max("sort"))["max_sort"] or 0

    def save(self, commit=True):
        if not self.instance.pk:
            self.instance.sort = self.get_max_sort() + 1
        self.instance.reindex_at = timezone.now()
        return super().save(commit)
