# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django import forms

#from ... import models
from .form import BaseModelFormMixin

__all__ = 'FormSetMixin',


class FormSetMixin(BaseModelFormMixin):

    extra = 1
    min_num = None
    max_num = None

    def get_extra(self, obj=None, **kwargs):
        """Hook for customizing the number of extra inline forms."""
        return self.extra

    def get_min_num(self, obj=None, **kwargs):
        """Hook for customizing the min number of inline forms."""
        return self.min_num

    def get_max_num(self, obj=None, **kwargs):
        """Hook for customizing the max number of extra inline forms."""
        return self.max_num

    def get_formset_class_kwargs(self, obj=None, **kwargs):
        # TODO: make common field getting logic work across form(set)s?
        # need fields=None in the event fields is missing to indicate "no call
        # to flatten get_fieldsets" which would recur
        # TODO: when a controller base class has fieldsets and it is concretely
        # inherited to make a second controller, the fieldsets are no longer
        # considered-- probably to do with options... FIXME
        FormsetForm = self.get_form_class(
            obj=obj,
            modelform_class=self.formset_form_class
        )

        # can_delete = self.can_delete and self.has_delete_permission(request, obj)
        # as it stands, can_delete is a concept only for inline controllers
        # we expect the non-inline formsets to get checkboxes for actions etc.
        extra = self.view.edit and self.get_extra(self, **kwargs) or 0
        can_delete = self.view.mode == 'edit' and self.has_permission('delete')

        defaults = dict(
            form=FormsetForm,
            formset=self.inlineformset_class if obj else self.formset_class,
            extra=extra,
            min_num=self.get_min_num(obj=obj, **kwargs),
            max_num=self.get_max_num(obj=obj, **kwargs),
            can_delete=can_delete,
        )
        # if form is model-derived, tack those kwargs onto the formset kwargs
        form_options = FormsetForm._meta
        if hasattr(form_options, 'model'):
            defaults.update(
                model=form_options.model,
                fields=form_options.fields,
                exclude=form_options.exclude,
                formfield_callback=self.formfield_for_dbfield,
                #**self.get_form_class_kwargs(
                #    view, form=self.formset_form, fields=fields)
            )

        if obj:
            defaults.setdefault('parent_model', self.fk.related_model)
            defaults.setdefault('fk_name', self.fk.name)

        # override with kwargs passed in last
        defaults.update(**kwargs)
        return defaults

    def get_formset_class(self, obj=None, **kwargs):
        """
        SOURCE: options.get_changelist_form(set)
        Returns an (Inline)FormSet class, as appropriate, for use as an inline
        formset on a given page, or as the change list for a list view.
        :param obj: The obj under which the FormSet will inline itself, if
        applicable.
        """

        formset_factory = (forms.inlineformset_factory
                           if obj
                           else forms.modelformset_factory)

        formset_kwargs = self.get_formset_class_kwargs(obj=obj, **kwargs)
        FormSet = formset_factory(**formset_kwargs)
        return FormSet

    def get_formset_kwargs(self, formset_class, obj=None,
                           queryset=None, **kwargs):
        # TODO: Not sure what this was doing for get_inline_formsets
        # if prefixes[prefix] != 1 or not prefix:
        #     prefix = "%s-%s" % (prefix, prefixes[prefix])
        formset_params = {
            'prefix': formset_class.get_default_prefix(),
            # views normally groom the QS and pass it in but not inlines
            'queryset': queryset if queryset is not None else self.get_queryset(),
            'view_controller': self,
            # 'is_readonly': not self.view.edit,
            'fieldsets': list(self.get_fieldsets(mode=self.view.mode)),
            'readonly_fields': list(self.get_readonly_fields(mode=self.view.mode)),
            'prepopulated_fields': dict(self.get_prepopulated_fields(mode=self.view.mode)),
        }
        if obj:
            formset_params['instance'] = obj
        if self.view.request.method == 'POST':
            formset_params.update({
                'data': self.view.request.POST,
                'files': self.view.request.FILES,
                #'save_as_new': '_saveasnew' in self.view.request.POST
            })

        return formset_params

    def get_formset(self, obj=None, queryset=None, **kwargs):
        # SOURCE: get_changelist_formset

        # to avoid any excess "magic", we will assume this is the AUTHORITATIVE
        # place to pass a parent_obj in, which will in turn determine whether
        # to setup as an (inline)formset -- constraining to an FK is JIT and
        # must be treated differently than auth-constraining a QS at a general,
        # bar-to-entry level -- DO NOT TRY TO MIX THE CONCEPTS--IT ENDS POORLY!

        FormSet = self.get_formset_class(obj=obj, **kwargs)
        formset_kwargs = self.get_formset_kwargs(
            formset_class=FormSet, obj=obj, queryset=queryset, **kwargs)
        return FormSet(**formset_kwargs)

    def errors(self):
        return self.formset.errors
