from django import forms
from django.core.exceptions import ImproperlyConfigured
from django.forms.widgets import SelectDateWidget
from django.utils.translation import gettext_lazy as _

from mezzanine.conf import settings
from mezzanine.core.forms import SplitSelectDateTimeWidget
from mezzanine.utils.importing import import_dotted_path

# Constants for all available field types.
TEXT = 1
TEXTAREA = 2
EMAIL = 3
CHECKBOX = 4
CHECKBOX_MULTIPLE = 5
SELECT = 6
SELECT_MULTIPLE = 7
RADIO_MULTIPLE = 8
FILE = 9
DATE = 10
DATE_TIME = 11
HIDDEN = 12
NUMBER = 13
URL = 14
DOB = 15

# Names for all available field types.
NAMES = (
    (TEXT, _("Single line text")),
    (TEXTAREA, _("Multi line text")),
    (EMAIL, _("Email")),
    (NUMBER, _("Number")),
    (URL, _("URL")),
    (CHECKBOX, _("Check box")),
    (CHECKBOX_MULTIPLE, _("Check boxes")),
    (SELECT, _("Drop down")),
    (SELECT_MULTIPLE, _("Multi select")),
    (RADIO_MULTIPLE, _("Radio buttons")),
    (FILE, _("File upload")),
    (DATE, _("Date")),
    (DATE_TIME, _("Date/time")),
    (DOB, _("Date of birth")),
    (HIDDEN, _("Hidden")),
)

# Field classes for all available field types.
CLASSES = {
    TEXT: forms.CharField,
    TEXTAREA: forms.CharField,
    EMAIL: forms.EmailField,
    CHECKBOX: forms.BooleanField,
    CHECKBOX_MULTIPLE: forms.MultipleChoiceField,
    SELECT: forms.ChoiceField,
    SELECT_MULTIPLE: forms.MultipleChoiceField,
    RADIO_MULTIPLE: forms.ChoiceField,
    FILE: forms.FileField,
    DATE: forms.DateField,
    DATE_TIME: forms.DateTimeField,
    DOB: forms.DateField,
    HIDDEN: forms.CharField,
    NUMBER: forms.FloatField,
    URL: forms.URLField,
}

# Widgets for field types where a specialised widget is required.
WIDGETS = {
    TEXTAREA: forms.Textarea,
    CHECKBOX_MULTIPLE: forms.CheckboxSelectMultiple,
    RADIO_MULTIPLE: forms.RadioSelect,
    DATE: SelectDateWidget,
    DATE_TIME: SplitSelectDateTimeWidget,
    DOB: SelectDateWidget,
    HIDDEN: forms.HiddenInput,
}

# Some helper groupings of field types.
CHOICES = (CHECKBOX, SELECT, RADIO_MULTIPLE)
DATES = (DATE, DATE_TIME, DOB)
MULTIPLE = (CHECKBOX_MULTIPLE, SELECT_MULTIPLE)

# HTML5 Widgets
html5_field = lambda name, base: type("", (base,), {"input_type": name})
if getattr(settings, "FORMS_USE_HTML5", False):
    WIDGETS.update(
        {
            DATE: html5_field("date", forms.DateInput),
            DATE_TIME: html5_field("datetime", forms.DateTimeInput),
            DOB: html5_field("date", forms.DateInput),
            EMAIL: html5_field("email", forms.TextInput),
            NUMBER: html5_field("number", forms.TextInput),
            URL: html5_field("url", forms.TextInput),
        }
    )

# Allow extra fields types to be defined via the FORMS_EXTRA_FIELDS
# setting, which should contain a sequence of three-item sequences,
# each containing the ID, dotted import path for the field class,
# and field name, for each custom field type.
extra_fields = getattr(settings, "FORMS_EXTRA_FIELDS", [])
for field_id, field_path, field_name in extra_fields:
    if field_id in CLASSES:
        err = "ID %s for field %s in FORMS_EXTRA_FIELDS already exists"
        raise ImproperlyConfigured(err % (field_id, field_name))
    CLASSES[field_id] = import_dotted_path(field_path)
    NAMES += ((field_id, _(field_name)),)

# Similar to above but for widgets - expects a sequence of pairs,
# each with a field ID as per above, and a dotted path to the custom
# widget class to use for the corresponding form field.
extra_widgets = getattr(settings, "FORMS_EXTRA_WIDGETS", [])
for field_id, widget_path in extra_widgets:
    if field_id not in CLASSES:
        err = "ID %s in FORMS_EXTRA_WIDGETS does not match a field"
        raise ImproperlyConfigured(err % field_id)
    WIDGETS[field_id] = import_dotted_path(widget_path)
