from django.forms.forms import BaseForm
from django.forms.widgets import media_property
from django.http import HttpResponseRedirect

from six import with_metaclass

from .constants import WIZARD_TYPE_COOKIE, WIZARD_TYPE_SESSION

from formtools.wizard.views import (
    CookieWizardView,
    SessionWizardView,
    WizardView,
)

from collections import OrderedDict

from django.urls import reverse

__title__ = 'fobi.dynamic'
__author__ = 'Artur Barseghyan <artur.barseghyan@gmail.com>'
__copyright__ = '2014-2017 Artur Barseghyan'
__license__ = 'GPL 2.0/LGPL 2.1'
__all__ = (
    'assemble_form_class',
    'assemble_form_wizard_class',
)

# ****************************************************************************
# ****************************************************************************
# **************************** Form generator ********************************
# ****************************************************************************
# ****************************************************************************


def assemble_form_class(form_entry, base_class=BaseForm, request=None,
                        origin=None, origin_kwargs_update_func=None,
                        origin_return_func=None, form_element_entries=None,
                        get_form_field_instances_kwargs={}):
    """Assemble a form class by given entry.

    :param form_entry:
    :param base_class:
    :param django.http.HttpRequest request:
    :param string origin:
    :param callable origin_kwargs_update_func:
    :param callable origin_return_func:
    :param iterable form_element_entries: If given, used instead of
        ``form_entry.formelemententry_set.all`` (no additional database hit).
    :param dict get_form_field_instances_kwargs: To be passed as **kwargs to
        the :method:`get_form_field_instances_kwargs`.
    """
    if form_element_entries is None:
        form_element_entries = form_entry.formelemententry_set.all()

    # DeclarativeFieldsMetaclass
    class DeclarativeFieldsMetaclass(type):
        """Declarative fields meta class.

        Copied from ``django.forms.forms.DeclarativeFieldsMetaclass``.

        Metaclass that converts Field attributes to a dictionary called
        `base_fields`, taking into account parent class 'base_fields' as well.
        """

        def __new__(cls, name, bases, attrs):
            """New."""
            base_fields = []

            for creation_counter, form_element_entry \
                    in enumerate(form_element_entries):
                plugin = form_element_entry.get_plugin(request=request)

                # We simply make sure the plugin exists. We don't handle
                # exceptions relate to the non-existent plugins here. They
                # are instead handled in registry.
                if plugin:
                    plugin_form_field_instances = \
                        plugin._get_form_field_instances(
                            form_element_entry=form_element_entry,
                            origin=origin,
                            kwargs_update_func=origin_kwargs_update_func,
                            return_func=origin_return_func,
                            extra={'counter': creation_counter},
                            request=request,
                            form_entry=form_entry,
                            form_element_entries=form_element_entries,
                            **get_form_field_instances_kwargs
                        )
                    for form_field_name, form_field_instance \
                            in plugin_form_field_instances:
                        base_fields.append(
                            (form_field_name, form_field_instance)
                        )

            attrs['base_fields'] = OrderedDict(base_fields)
            new_class = super(DeclarativeFieldsMetaclass, cls).__new__(
                cls, name, bases, attrs
            )

            if 'media' not in attrs:
                new_class.media = media_property(new_class)

            return new_class

    # DynamicForm
    class DynamicForm(with_metaclass(DeclarativeFieldsMetaclass, base_class)):
        """Dynamically created form element plugin class."""

    # Finally, return the DynamicForm
    return DynamicForm
