from django.db.models.fields.related import ForeignKey, ManyToManyField
from django.forms.models import ModelForm
from django.utils.encoding import force_text
from django.utils.text import capfirst
from django.utils.translation import ugettext_lazy as _


def make_ajax_form(model, fieldlist, superclass=ModelForm, show_help_text=False, **kwargs):
    """Creates a ModelForm subclass with AutoComplete fields.

    Args:
        model (type): Model class for which you are making the ModelForm
        fieldlist (dict): {field_name -> channel_name, ...}
        superclass (type): optional ModelForm superclass
        show_help_text (bool): suppress or show the widget help text

    Returns:
        ModelForm: a ModelForm suitable for use in an Admin

    Usage::

        from django.contrib import admin
        from ajax_select import make_ajax_form
        from yourapp.models import YourModel

        @admin.register(YourModel)
        class YourModelAdmin(Admin):

            form = make_ajax_form(YourModel, {
                'contacts': 'contact',  # ManyToManyField
                'author':'contact'      # ForeignKeyField
            })

    Where 'contacts' is a ManyToManyField specifying to use the lookup channel 'contact'
    and 'author' is a ForeignKeyField specifying here to also use the same lookup channel 'contact'

    """
    # will support previous arg name for several versions before deprecating
    # TODO: time to go
    if 'show_m2m_help' in kwargs:
        show_help_text = kwargs.pop('show_m2m_help')

    class TheForm(superclass):

        class Meta:
            exclude = []

        setattr(Meta, 'model', model)
        if hasattr(superclass, 'Meta'):
            if hasattr(superclass.Meta, 'fields'):
                setattr(Meta, 'fields', superclass.Meta.fields)
            if hasattr(superclass.Meta, 'exclude'):
                setattr(Meta, 'exclude', superclass.Meta.exclude)
            if hasattr(superclass.Meta, 'widgets'):
                setattr(Meta, 'widgets', superclass.Meta.widgets)

    for model_fieldname, channel in fieldlist.items():
        f = make_ajax_field(model, model_fieldname, channel, show_help_text)

        TheForm.declared_fields[model_fieldname] = f
        TheForm.base_fields[model_fieldname] = f

    return TheForm


def make_ajax_field(related_model, fieldname_on_model, channel, show_help_text=False, **kwargs):
    """Makes an AutoComplete field for use in a Form.

    Args:
        related_model (Model): model of the related object
        fieldname_on_model (str): field name on the model being edited
        channel (str): channel name of a registered LookupChannel
        show_help_text (bool): show or supress help text below the widget
            Django admin will show help text below the widget, but not for ManyToMany inside of admin inlines
            This setting will show the help text inside the widget itself.
        kwargs: optional args

            - help_text: default is the model db field's help_text.
                            None will disable all help text
            - label: default is the model db field's verbose name
            - required: default is the model db field's (not) blank

    Returns:
        (AutoCompleteField, AutoCompleteSelectField, AutoCompleteSelectMultipleField): field
    """
    from ajax_select.fields import AutoCompleteField, \
        AutoCompleteSelectMultipleField, \
        AutoCompleteSelectField

    field = related_model._meta.get_field(fieldname_on_model)
    if 'label' not in kwargs:
        kwargs['label'] = _(capfirst(force_text(field.verbose_name)))

    if ('help_text' not in kwargs) and field.help_text:
        kwargs['help_text'] = field.help_text
    if 'required' not in kwargs:
        kwargs['required'] = not field.blank

    kwargs['show_help_text'] = show_help_text
    if isinstance(field, ManyToManyField):
        f = AutoCompleteSelectMultipleField(
            channel,
            **kwargs)
    elif isinstance(field, ForeignKey):
        f = AutoCompleteSelectField(
            channel,
            **kwargs)
    else:
        f = AutoCompleteField(
            channel,
            **kwargs)
    return f
