from django import forms
from django.forms.models import BaseInlineFormSet
from django.template import loader
from django.utils import timezone

from bda.models import Attribution, Spectacle, SpectacleRevente


class InscriptionInlineFormSet(BaseInlineFormSet):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # self.instance is a Participant object
        tirage = self.instance.tirage

        # set once for all "spectacle" field choices
        # - restrict choices to the spectacles of this tirage
        # - force_choices avoid many db requests
        spectacles = tirage.spectacle_set.select_related("location")
        choices = [(sp.pk, str(sp)) for sp in spectacles]
        self.force_choices("spectacle", choices)

    def force_choices(self, name, choices):
        """Set choices of a field.

        As ModelChoiceIterator (default use to get choices of a
        ModelChoiceField), it appends an empty selection if requested.

        """
        for form in self.forms:
            field = form.fields[name]
            if field.empty_label is not None:
                field.choices = [("", field.empty_label)] + choices
            else:
                field.choices = choices


class TokenForm(forms.Form):
    token = forms.CharField(widget=forms.widgets.Textarea())


class TemplateLabelField(forms.ModelMultipleChoiceField):
    """
    Extends ModelMultipleChoiceField to offer two more customization options :
    - `label_from_instance` can be used with a template file
    - the widget rendering template can be specified with `option_template_name`
    """

    def __init__(
        self,
        label_template_name=None,
        context_object_name="obj",
        option_template_name=None,
        *args,
        **kwargs
    ):
        super().__init__(*args, **kwargs)
        self.label_template_name = label_template_name
        self.context_object_name = context_object_name
        if option_template_name is not None:
            self.widget.option_template_name = option_template_name

    def label_from_instance(self, obj):
        if self.label_template_name is None:
            return super().label_from_instance(obj)
        else:
            return loader.render_to_string(
                self.label_template_name, context={self.context_object_name: obj}
            )


# Formulaires pour revente_manage


class ResellForm(forms.Form):
    def __init__(self, participant, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["attributions"] = TemplateLabelField(
            queryset=participant.attribution_set.filter(
                spectacle__date__gte=timezone.now()
            )
            .exclude(revente__seller=participant)
            .select_related("spectacle", "spectacle__location", "participant__user"),
            widget=forms.CheckboxSelectMultiple,
            required=False,
            label_template_name="bda/forms/attribution_label_table.html",
            option_template_name="bda/forms/checkbox_table.html",
            context_object_name="attribution",
        )


class AnnulForm(forms.Form):
    def __init__(self, participant, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["reventes"] = TemplateLabelField(
            label="",
            queryset=participant.original_shows.filter(
                attribution__spectacle__date__gte=timezone.now(), soldTo__isnull=True
            )
            .select_related(
                "attribution__spectacle", "attribution__spectacle__location"
            )
            .order_by("-date"),
            widget=forms.CheckboxSelectMultiple,
            required=False,
            label_template_name="bda/forms/revente_self_label_table.html",
            option_template_name="bda/forms/checkbox_table.html",
            context_object_name="revente",
        )


class SoldForm(forms.Form):
    def __init__(self, participant, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["reventes"] = TemplateLabelField(
            queryset=participant.original_shows.filter(soldTo__isnull=False)
            .exclude(soldTo=participant)
            .select_related(
                "attribution__spectacle", "attribution__spectacle__location"
            ),
            widget=forms.CheckboxSelectMultiple,
            label_template_name="bda/forms/revente_sold_label_table.html",
            option_template_name="bda/forms/checkbox_table.html",
            context_object_name="revente",
        )


# Formulaire pour revente_subscribe


class InscriptionReventeForm(forms.Form):
    def __init__(self, tirage, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["spectacles"] = TemplateLabelField(
            queryset=tirage.spectacle_set.select_related("location").filter(
                date__gte=timezone.now()
            ),
            widget=forms.CheckboxSelectMultiple,
            required=False,
            label_template_name="bda/forms/spectacle_label_table.html",
            option_template_name="bda/forms/checkbox_table.html",
            context_object_name="spectacle",
        )


# Formulaires pour revente_tirages


class ReventeTirageAnnulForm(forms.Form):
    def __init__(self, participant, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["reventes"] = TemplateLabelField(
            queryset=participant.entered.filter(soldTo__isnull=True).select_related(
                "attribution__spectacle", "seller__user"
            ),
            widget=forms.CheckboxSelectMultiple,
            required=False,
            label_template_name="bda/forms/revente_other_label_table.html",
            option_template_name="bda/forms/checkbox_table.html",
            context_object_name="revente",
        )


class ReventeTirageForm(forms.Form):
    def __init__(self, participant, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.fields["reventes"] = TemplateLabelField(
            queryset=(
                SpectacleRevente.objects.filter(
                    notif_sent=True,
                    shotgun=False,
                    tirage_done=False,
                    attribution__spectacle__tirage=participant.tirage,
                )
                .exclude(confirmed_entry=participant)
                .select_related("attribution__spectacle")
            ),
            widget=forms.CheckboxSelectMultiple,
            required=False,
            label_template_name="bda/forms/revente_other_label_table.html",
            option_template_name="bda/forms/checkbox_table.html",
            context_object_name="revente",
        )