import django
from django.conf import settings
from django.core.exceptions import ValidationError
from django.forms.formsets import formset_factory
from django.template import Context, Template
from django.test import TestCase
from django.utils.translation import gettext_lazy as _

import floppyforms as forms
from .base import InvalidVariable
from .compat import unittest

skipIf = unittest.skipIf


def render(template, context=None):
    if context is None:
        context = {}
    c = Context(context)
    t = Template('{% load floppyforms %}' + template)
    return t.render(c)


class HiddenForm(forms.Form):
    hide = forms.CharField(widget=forms.HiddenInput())


class OneFieldForm(forms.Form):
    text = forms.CharField()

    def clean(self):
        if self.errors:
            raise ValidationError('Please correct the errors below.')


class ShortForm(forms.Form):
    name = forms.CharField(label=_('Your first name?'))
    age = forms.IntegerField(required=False)
    metadata = forms.CharField(required=False, widget=forms.HiddenInput)


class RegistrationForm(forms.Form):
    honeypot = forms.CharField(required=False, widget=forms.HiddenInput)
    firstname = forms.CharField(label=_('Your first name?'))
    lastname = forms.CharField(label=_('Your last name:'))
    username = forms.CharField(max_length=30)
    password = forms.CharField(
        widget=forms.PasswordInput,
        help_text=_('Make sure to use a secure password.'),
    )
    password2 = forms.CharField(label=_('Retype password'), widget=forms.PasswordInput)
    age = forms.IntegerField(required=False)

    def clean_honeypot(self):
        if self.cleaned_data.get('honeypot'):
            raise ValidationError('Haha, you trapped into the honeypot.')
        return self.cleaned_data['honeypot']

    def clean(self):
        if self.errors:
            raise ValidationError('Please correct the errors below.')


class PLayoutTests(TestCase):
    def test_layout(self):
        form = RegistrationForm()
        with self.assertTemplateUsed('floppyforms/layouts/p.html'):
            with self.assertTemplateUsed('floppyforms/rows/p.html'):
                layout = render('{% form form using "floppyforms/layouts/p.html" %}', {'form': form})
        self.maxDiff = None
        self.assertHTMLEqual(layout, """
        <p><label for="id_firstname">Your first name?</label> <input type="text" name="firstname" id="id_firstname" required />
        </p>
        <p><label for="id_lastname">Yo
ur last name:</label> <input type="text" name="lastname" id="id_lastname" required />
        </p>
        <p><label for="id_username">Username:</label> <input type="text" name="username" id="id_username" maxlength="30" required />
        </p>
        <p><label for="id_password">Password:</label> <input type="password" name="password" id="id_password" required />
         <span class="helptext">Make sure to use a secure password.</span></p>
        <p><label for="id_password2">Retype password:</label> <inp
ut type="password" name="password2" id="id_password2" required />
        </p>
        <p><label for="id_age">Age:</label> <input type="number" name="age" id="id_age" />
        <input type="hidden" name="honeypot" id="id_honeypot" />
        </p>
        """)

    def test_layout_with_errors(self):
        form = RegistrationForm({'non_field_errors': True})
        layout = render('{% form form using "floppyforms/layouts/p.html" %}', {'form': form})
        self.maxDiff = None
        self.assertHTMLEqual(layout, """
        <ul class="errorlist"><li>Please correct the errors below.</li></ul>
        <ul class="errorlist"><li>This field is required.</li></ul>
        <p><label for="id_firstname">Your first name?</label> <input type="text" name="firstname" id="id_firstname" required /></p>
        <ul class="errorlist"><li>This field is required.</li></ul>
        <p><label for="id_lastname">Your last name:</label> <input type="text" name="lastname" id="id_lastname" required /></p>
        <ul class="errorlist"><li>This field is required.</li></ul>
        <p><label for="id_username">Username:</label> <input type="text" name="username" id="id_username" maxlength="30" required /></p>
        <ul class="errorlist"><li>This field is required.</li></ul>
        <p>
            <label for="id_password">Password:</label> <input type="password" name="password" id="id_password" required />
            <span class="helptext">Make sure to use a secure password.</span>
        </p>
        <ul class="errorlist"><li>This field is required.</li></ul>
        <p><label for="id_password2">Retype password:</label> <input type="password" name="password2" id="id_password2" required /></p>
        <p><label for="id_age">Age:</label> <input type="number" name="age" id="id_age" />
            <input type="hidden" name="honeypot" id="id_honeypot" /></p>
        """)

        form = RegistrationForm({'non_field_errors': True, 'honeypot': 1})
        layout = render('{% form form using "floppyforms/layouts/p.html" %}', {'form': form})
        self.assertHTMLEqual(layout, """
        <ul class="errorlist">
            <li>Please correct the errors below.</li>
            <li>Haha, you trapped into the honeypot.</li>
        </ul>
        <ul class="errorlist"><li>This field is required.</li></ul>
        <p><label for="id_firstname">Your first name?</label> <input type="text" name="firstname" id="id_firstname" required /></p>
        <ul class="errorlist"><li>This field is required.</li></ul>
        <p><label for="id_lastname">Your last name:</label> <input type="text" name="lastname" id="id_lastname" required /></p>
        <ul class="errorlist"><li>This field is required.</li></ul>
        <p><label for="id_username">Username:</label> <input type="text" name="username" id="id_username" maxlength="30" required /></p>
        <ul class="errorlist"><li>This field is required.</li></ul>
        <p>
            <label for="id_password">Password:</label> <input type="password" name="password" id="id_password" required />
            <span class="helptext">Make sure to use a secure password.</span>
        </p>
        <ul class="errorlist"><li>This field is required.</li></ul>
        <p><label for="id_password2">Retype password:</label> <input type="password" name="password2" id="id_password2" required /></p>
        <p><label for="id_age">Age:</label> <input type="number" name="age" id="id_age" />
            <input type="hidden" name="honeypot" id="id_honeypot" value="1" /></p>
        """)

    def test_layout_with_custom_label(self):
        form = OneFieldForm()
        layout = render("""
            {% form form using %}
                {% formrow form.text using "floppyforms/rows/p.html" with label="Custom label" %}
            {% endform %}
        """, {'form': form})
        self.assertHTMLEqual(layout, """
        <p><label for="id_text">Custom label:</label> <input type="text" name="text" id="id_text" required /></p>
        """)

    def test_layout_with_custom_help_text(self):
        form = OneFieldForm()
        layout = render("""
            {% form form using %}
                {% formrow form.text using "floppyforms/rows/p.html" with help_text="Would you mind entering text here?" %}
            {% endform %}
        """, {'form': form})
        self.assertHTMLEqual(layout, """
        <p>
            <label for="id_text">Text:</label> <input type="text" name="text" id="id_text" required />
            <span class="helptext">Would you mind entering text here?</span>
        </p>
        """)

    def test_hidden_only_fields(self):
        form = HiddenForm()
        rendered = render("""{% form form using "floppyforms/layouts/p.html" %}""", {'form': form})
        self.assertHTMLEqual(rendered, """
        <input type="hidden" name="hide" id="id_hide" required>
        """)

    def test_formsets_with_hidden_fields(self):
        ShortFormset = formset_factory(form=ShortForm, extra=1)
        formset = ShortFormset(initial=[{'name': 'Johnson', 'age': 23, 'metadata': 'Hidden details'}])
        rendered = render("""{% form formset using "floppyforms/layouts/p.html" %}""", {'formset': for