import datetime
import string

from django import forms
from django.contrib.auth import (
    authenticate, get_user_model, password_validation,
)
from django.contrib.auth.forms import _unicode_ci_compare, SetPasswordForm
from django.contrib.auth.password_validation import validate_password
from django.contrib.auth.tokens import default_token_generator
from django.contrib.sites.shortcuts import get_current_site
from django.core.exceptions import ValidationError
from django.core.mail import EmailMultiAlternatives
from django.core.validators import RegexValidator
from django.forms import ModelForm
from django.template import loader
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode
from django.utils.translation import gettext_lazy as _

from meals.models import Meal
from .models import User
from orderitems.models import OrderItem


UserModel = get_user_model()

years = []
for year in range(1900,2022):
    years.append(year)


class UserSignUpForm(forms.ModelForm):
    """
    A custom form used by UserSignUpView for when an unauthenticated user creates an account.
    Widgets for each field are assigned so that a bootstrap class of 'form-control' could be added
    to each widget. The date_of_birth field's input format is set as MM/DD/YYYY in the widget.
    """


    password1 = forms.CharField(label='Password', widget=forms.PasswordInput(attrs={'class':'form-control'}))
    password2 = forms.CharField(label='<PASSWORD>', widget=forms.PasswordInput(attrs={'class':'form-control'}))
    date_of_birth = forms.DateField(label='Birthday', initial= datetime.date.today(), widget=forms.SelectDateWidget(years=years, attrs={'class': 'form-control'}))

    class Meta:
        model = User
        fields = ('email','name', 'date_of_birth', 'phone_number', 'street_address', 'city', 'state', 'zip_code')

        widgets = {
            'email': forms.EmailInput(attrs={'class': 'form-control'}),
            'name': forms.TextInput(attrs={'class': 'form-control'}),
            'phone_number': forms.TextInput(attrs={'class': 'form-control'}),
            'street_address': forms.TextInput(attrs={'class': 'form-control'}),
            'city': forms.TextInput(attrs={'class': 'form-control'}),
            'state': forms.Select(attrs={'class': 'form-control'}),
            'zip_code': forms.TextInput(attrs={'class': 'form-control'}),
        }

        labels = {
            'name': 'Full name'
        }

    def clean_email(self):
        email = self.cleaned_data['email']
        return email.lower()
        # return email

    def clean_password2(self):
        password1 = self.cleaned_data.get("password1")
        password2 = self.cleaned_data.get("password2")
        if password1 and password2 and password1 != password2:
            raise forms.ValidationError("Passwords don't match")
        validate_password(password2)
        return password2

    def save(self, *args, **kwargs):
        user = super().save(commit=False)
        user.set_password(self.cleaned_data["password2"])
        user.save()
        return user


class UserUpdateForm(forms.ModelForm):
    """
    A custom form used by UserProfileUpdateView to allow authenticated users to update their profile
    information. Widgets for each field are assigned so that a bootstrap class of 'form-control'
    could be added to each widget. The date_of_birth field's input format is set as MM/DD/YYYY in the widget.
    """

    class Meta:
        model = User
        fields = ('name', 'date_of_birth', 'phone_number', 'street_address', 'city', 'state', 'zip_code')

        widgets = {
            'name': forms.TextInput(attrs={'class': 'form-control'}),
            'date_of_birth': forms.SelectDateWidget(years=years, attrs={'class': 'form-control'}),
            'phone_number': forms.TextInput(attrs={'class': 'form-control'}),
            'street_address': forms.TextInput(attrs={'class': 'form-control'}),
            'city': forms.TextInput(attrs={'class': 'form-control'}),
            'state': forms.Select(attrs={'class': 'form-control'}),
            'zip_code': forms.TextInput(attrs={'class': 'form-control'}),
        }
        
        labels = {
            'name': 'Full name'
        }



#Copied from SetPasswordForm
class CustomUserSetPasswordForm(forms.Form):
    """
    A form that lets a user change set their password without entering the old
    password. This was copied over from SetPasswordForm, which is used by the class_form = PasswordChangeForm that is used
    by the generic PasswordChangeView. This was copied over so that the bootstrap class 'form-control' could be added
    to each widget to allow for bootstrap styling.
    """

    error_messages = {
        'password_mismatch': _('The two password fields didn’t match.'),
    }
    new_password1 = forms.CharField(
        label=_("New password"),
        widget=forms.PasswordInput(attrs={'autocomplete': 'new-password', 'class': 'form-control'}),
        strip=False,
        help_text=password_validation.password_validators_help_text_html(),
    )
    new_password2 = forms.CharField(
        label=_("New password confirmation"),
        strip=False,
        widget=forms.PasswordInput(attrs={'autocomplete': 'new-password', 'class': 'form-control'}),
    )

    def __init__(self, user, *args, **kwargs):
        self.user = user
        super().__init__(*args, **kwargs)

    def clean_new_password2(self):
        password1 = self.cleaned_data.get('<PASSWORD>')
        password2 = self.cleaned_data.get('<PASSWORD>')
        if password1 and password2:
            if password1 != password2:
                raise ValidationError(
                    self.error_messages['password_mismatch'],
                    code='password_mismatch',
                )
        password_validation.validate_password(password2, self.user)
        return password2

    def save(self, commit=True):
        password = self.cleaned_data["<PASSWORD>"]
        self.user.set_password(password)
        if commit:
            self.user.save()
        return self.user

#Copied from PasswordChangeForm
class CustomUserPasswordChangeForm(CustomUserSetPasswordForm):
    """
    A form that lets a user change their password by entering their old
    password. This was copied from the PasswordChangeForm, which is the class_form for the generic
    PasswordChangeView. This was copied over so that the bootstrap class 'form-control' could be added
    to each widget to allow for bootstrap styling.
    """

    error_messages = {
        **SetPasswordForm.error_messages,
        'password_incorrect': _("Your old password was entered incorrectly. Please enter it again."),
    }
    old_password = forms.CharField(
        label=_("Old password"),
        strip=False,
        widget=forms.PasswordInput(attrs={'autocomplete': 'current-password', 'autofocus': True, 'class':'form-control'}),
    )

    field_order = ['old_password', 'new_password1', 'new_password2']

    def clean_old_password(self):
        """
        Validate that the old_password field is correct.
        """
        old_password = self.cleaned_data["old_password"]
        if not self.user.check_password(old_password):
            raise ValidationError(
                self.error_messages['password_incorrect'],
                code='password_incorrect',
            )
        return old_password


class CustomPasswordResetForm(forms.Form):
    email = forms.EmailField(
        label=_("Email"),
        max_length=254,
        widget=forms.EmailInput(attrs={'autocomplete': 'email', 'class': 'form-control'})
    )

    def send_mail(self, subject_template_name, email_template_name,
                  context, from_email, to_email, html_email_template_name=None):
        """
        Send a django.core.mail.EmailMultiAlternatives to `to_email`.
        """
        subject = loader.render_to_string(subject_template_name, context)
        # Email subject *must not* contain newlines
        subject = ''.join(subject.splitlines())
        body = loader.render_to_string(email_template_name, context)

        email_message = EmailMultiAlternatives(subject, body, from_email, [to_email])
        if html_email_template_name is not None:
            html_email = loader.render_to_string(html_email_template_name, context)
            email_message.attach_alternative(html_email, 'text/html')

        email_message.send()

    def get_users(self, email):
        """Given an email, return matching user(s) who should receive a reset.

        This allows subclasses to more easily customize the default policies
        that prevent inactive users and users with unusable passwords from
        resetting their password.
        """
        email_field_name = UserModel.get_email_field_name()
        active_users = UserModel._default_manager.filter(**{
            '%s__iexact' % email_field_name: email,
            'is_active': True,
        })
        return (
            u for u in active_users
            if u.has_usable_password() and
            _unicode_ci_compare(email, getattr(u, email_field_name))
        )

    def save(self, domain_override=None,
             subject_template_name='registration/password_reset_subject.txt',
             email_template_name='registration/password_reset_email.html',
             use_https=False, token_generator=default_token_generator,
             from_email=None, request=None, html_email_template_name=None,
             extra_email_context=None):
        """
        Generate a one-use only link for resetting password and send it to the
        user.
        """
        email = self.cleaned_data["email"]
        if not domain_override:
            current_site = get_current_site(request)
            site_name = current_site.name
            domain = current_site.domain
        else:
            site_name = domain = domain_override
        email_field_name = UserModel.get_email_field_name()
        for user in self.get_users(email):
            user_email = getattr(user, email_field_name)
            context = {
                'email': user_email,
                'domain': domain,
                'site_name': site_name,
                'uid': urlsafe_base64_encode(force_bytes(user.pk)),
                'user': user,
                'token': token_generator.make_token(user),
                'protocol': 'https' if use_https else 'http',
                **(extra_email_context or {}),
            }
            self.send_mail(
                subject_template_name, email_template_name, context, from_email,
                user_email, html_email_template_name=html_email_template_name,
            )

class CustomPasswordSetForm(forms.Form):
    """
    A form that lets a user change set their password without entering the old
    password
    """
    error_messages = {
        'password_mismatch': _('The two password fields didn’t match.'),
    }
    new_password1 = forms.CharField(
        label=_("New password"),
        widget=forms.PasswordInput(attrs={'autocomplete': 'new-password', 'class': 'form-control'}),
        strip=False,
        # help_text=password_validation.password_validators_help_text_html(),
    )
    new_password2 = forms.CharField(
        label=_("New password confirmation"),
        strip=False,
        widget=forms.PasswordInput(attrs={'autocomplete': 'new-password', 'class': 'form-control'}),
    )

    def __init__(self, user, *args, **kwargs):
        self.user = user
        super().__init__(*args, **kwargs)

    def clean_new_password2(self):
        password1 = self.cleaned_data.get('<PASSWORD>')
        password2 = self.cleaned_data.get('<PASSWORD>')
        if password1 and password2:
            if password1 != <PASSWORD>:
                raise ValidationError(
                    self.error_messages['password_mismatch'],
                    code='password_mismatch',
                )
        password_validation.validate_password(password2, self.user)
        return password2

    def save(self, commit=True):
        password = self.cleaned_data["<PASSWORD>"]
        self.user.set_password(password)
        if commit:
            self.user.save()
        return self.user


import datetime
import string

from django import forms
from django.contrib.auth import (
    authenticate, get_user_model, password_validation,
)
from django.contrib.auth.forms import _unicode_ci_compare, SetPasswordForm
from django.contrib.auth.password_validation import validate_password
from django.contrib.auth.tokens import default_token_generator
from django.contrib.sites.shortcuts import get_current_site
from django.core.exceptions import ValidationError
from django.core.mail import EmailMultiAlternatives
from django.core.validators import RegexValidator
from django.forms import ModelForm
from django.template import loader
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode
from django.utils.translation import gettext_lazy as _

from meals.models import Meal
from .models import User
from orderitems.models import OrderItem


UserModel = get_user_model()

years = []
for year in range(1900,2022):
    years.append(year)


class UserSignUpForm(forms.ModelForm):
    """
    A custom form used by UserSignUpView for when an unauthenticated user creates an account.
    Widgets for each field are assigned so that a bootstrap class of 'form-control' could be added
    to each widget. The date_of_birth field's input format is set as MM/DD/YYYY in the widget.
    """


    password1 = forms.CharField(label='Password', widget=forms.PasswordInput(attrs={'class':'form-control'}))
    password2 = forms.CharField(label='<PASSWORD>', widget=forms.PasswordInput(attrs={'class':'form-control'}))
    date_of_birth = forms.DateField(label='Birthday', initial= datetime.date.today(), widget=forms.SelectDateWidget(years=years, attrs={'class': 'form-control'}))

    class Meta:
        model = User
        fields = ('email','name', 'date_of_birth', 'phone_number', 'street_address', 'city', 'state', 'zip_code')

        widgets = {
            'email': forms.EmailInput(attrs={'class': 'form-control'}),
            'name': forms.TextInput(attrs={'class': 'form-control'}),
            'phone_number': forms.TextInput(attrs={'class': 'form-control'}),
            'street_address': forms.TextInput(attrs={'class': 'form-control'}),
            'city': forms.TextInput(attrs={'class': 'form-control'}),
            'state': forms.Select(attrs={'class': 'form-control'}),
            'zip_code': forms.TextInput(attrs={'class': 'form-control'}),
        }

        labels = {
            'name': 'Full name'
        }

    def clean_email(self):
        email = self.cleaned_data['email']
        return email.lower()
        # return email

    def clean_password2(self):
        password1 = self.cleaned_data.get("password1")
        password2 = self.cleaned_data.get("password2")
        if password1 and password2 and password1 != password2:
            raise forms.ValidationError("Passwords don't match")
        validate_password(password2)
        return password2

    def save(self, *args, **kwargs):
        user = super().save(commit=False)
        user.set_password(self.cleaned_data["password2"])
        user.save()
        return user


class UserUpdateForm(forms.ModelForm):
    """
    A custom form used by UserProfileUpdateView to allow authenticated users to update their profile
    information. Widgets for each field are assigned so that a bootstrap class of 'form-control'
    could be added to each widget. The date_of_birth field's input format is set as MM/DD/YYYY in the widget.
    """

    class Meta:
        model = User
        fields = ('name', 'date_of_birth', 'phone_number', 'street_address', 'city', 'state', 'zip_code')

        widgets = {
            'name': forms.TextInput(attrs={'class': 'form-control'}),
            'date_of_birth': forms.SelectDateWidget(years=years, attrs={'class': 'form-control'}),
            'phone_number': forms.TextInput(attrs={'class': 'form-control'}),
            'street_address': forms.TextInput(attrs={'class': 'form-control'}),
            'city': forms.TextInput(attrs={'class': 'form-control'}),
            'state': forms.Select(attrs={'class': 'form-control'}),
            'zip_code': forms.TextInput(attrs={'class': 'form-control'}),
        }
        
        labels = {
            'name': 'Full name'
        }



#Copied from SetPasswordForm
class CustomUserSetPasswordForm(forms.Form):
    """
    A form that lets a user change set their password without entering the old
    password. This was copied over from SetPasswordForm, which is used by the class_form = PasswordChangeForm that is used
    by the generic PasswordChangeView. This was copied over so that the bootstrap class 'form-control' could be added
    to each widget to allow for bootstrap styling.
    """

    error_messages = {
        'password_mismatch': _('The two password fields didn’t match.'),
    }
    new_password1 = forms.CharField(
        label=_("New password"),
        widget=forms.PasswordInput(attrs={'autocomplete': 'new-password', 'class': 'form-control'}),
        strip=False,
        help_text=password_validation.password_validators_help_text_html(),
    )
    new_password2 = forms.CharField(
        label=_("New password confirmation"),
        strip=False,
        widget=forms.PasswordInput(attrs={'autocomplete': 'new-password', 'class': 'form-control'}),
    )

    def __init__(self, user, *args, **kwargs):
        self.user = user
        super().__init__(*args, **kwargs)

    def clean_new_password2(self):
        password1 = self.cleaned_data.get('<PASSWORD>')
        password2 = self.cleaned_data.get('<PASSWORD>')
        if password1 and password2:
            if password1 != password2:
                raise ValidationError(
                    self.error_messages['password_mismatch'],
                    code='password_mismatch',
                )
        password_validation.validate_password(password2, self.user)
        return password2

    def save(self, commit=True):
        password = self.cleaned_data["<PASSWORD>"]
        self.user.set_password(password)
        if commit:
            self.user.save()
        return self.user

#Copied from PasswordChangeForm
class CustomUserPasswordChangeForm(CustomUserSetPasswordForm):
    """
    A form that lets a user change their password by entering their old
    password. This was copied from the PasswordChangeForm, which is the class_form for the generic
    PasswordChangeView. This was copied over so that the bootstrap class 'form-control' could be added
    to each widget to allow for bootstrap styling.
    """

    error_messages = {
        **SetPasswordForm.error_messages,
        'password_incorrect': _("Your old password was entered incorrectly. Please enter it again."),
    }
    old_password = forms.CharField(
        label=_("Old password"),
        strip=False,
        widget=forms.PasswordInput(attrs={'autocomplete': 'current-password', 'autofocus': True, 'class':'form-control'}),
    )

    field_order = ['old_password', 'new_password1', 'new_password2']

    def clean_old_password(self):
        """
        Validate that the old_password field is correct.
        """
        old_password = self.cleaned_data["old_password"]
        if not self.user.check_password(old_password):
            raise ValidationError(
                self.error_messages['password_incorrect'],
                code='password_incorrect',
            )
        return old_password


class CustomPasswordResetForm(forms.Form):
    email = forms.EmailField(
        label=_("Email"),
        max_length=254,
        widget=forms.EmailInput(attrs={'autocomplete': 'email', 'class': 'form-control'})
    )

    def send_mail(self, subject_template_name, email_template_name,
                  context, from_email, to_email, html_email_template_name=None):
        """
        Send a django.core.mail.EmailMultiAlternatives to `to_email`.
        """
        subject = loader.render_to_string(subject_template_name, context)
        # Email subject *must not* contain newlines
        subject = ''.join(subject.splitlines())
        body = loader.render_to_string(email_template_name, context)

        email_message = EmailMultiAlternatives(subject, body, from_email, [to_email])
        if html_email_template_name is not None:
            html_email = loader.render_to_string(html_email_template_name, context)
            email_message.attach_alternative(html_email, 'text/html')

        email_message.send()

    def get_users(self, email):
        """Given an email, return matching user(s) who should receive a reset.

        This allows subclasses to more easily customize the default policies
        that prevent inactive users and users with unusable passwords from
        resetting their password.
        """
        email_field_name = UserModel.get_email_field_name()
        active_users = UserModel._default_manager.filter(**{
            '%s__iexact' % email_field_name: email,
            'is_active': True,
        })
        return (
            u for u in active_users
            if u.has_usable_password() and
            _unicode_ci_compare(email, getattr(u, email_field_name))
        )

    def save(self, domain_override=None,
             subject_template_name='registration/password_reset_subject.txt',
             email_template_name='registration/password_reset_email.html',
             use_https=False, token_generator=default_token_generator,
             from_email=None, request=None, html_email_template_name=None,
             extra_email_context=None):
        """
        Generate a one-use only link for resetting password and send it to the
        user.
        """
        email = self.cleaned_data["email"]
        if not domain_override:
            current_site = get_current_site(request)
            site_name = current_site.name
            domain = current_site.domain
        else:
            site_name = domain = domain_override
        email_field_name = UserModel.get_email_field_name()
        for user in self.get_users(email):
            user_email = getattr(user, email_field_name)
            context = {
                'email': user_email,
                'domain': domain,
                'site_name': site_name,
                'uid': urlsafe_base64_encode(force_bytes(user.pk)),
                'user': user,
                'token': token_generator.make_token(user),
                'protocol': 'https' if use_https else 'http',
                **(extra_email_context or {}),
            }
            self.send_mail(
                subject_template_name, email_template_name, context, from_email,
                user_email, html_email_template_name=html_email_template_name,
            )

class CustomPasswordSetForm(forms.Form):
    """
    A form that lets a user change set their password without entering the old
    password
    """
    error_messages = {
        'password_mismatch': _('The two password fields didn’t match.'),
    }
    new_password1 = forms.CharField(
        label=_("New password"),
        widget=forms.PasswordInput(attrs={'autocomplete': 'new-password', 'class': 'form-control'}),
        strip=False,
        # help_text=password_validation.password_validators_help_text_html(),
    )
    new_password2 = forms.CharField(
        label=_("New password confirmation"),
        strip=False,
        widget=forms.PasswordInput(attrs={'autocomplete': 'new-password', 'class': 'form-control'}),
    )

    def __init__(self, user, *args, **kwargs):
        self.user = user
        super().__init__(*args, **kwargs)

    def clean_new_password2(self):
        password1 = self.cleaned_data.get('<PASSWORD>')
        password2 = self.cleaned_data.get('<PASSWORD>')
        if password1 and password2:
            if password1 != <PASSWORD>:
                raise ValidationError(
                    self.error_messages['password_mismatch'],
                    code='password_mismatch',
                )
        password_validation.validate_password(password2, self.user)
        return password2

    def save(self, commit=True):
        password = self.cleaned_data["<PASSWORD>"]
        self.user.set_password(password)
        if commit:
            self.user.save()
        return self.user


A custom form used by UserSignUpView for when an unauthenticated user creates an account.     Widgets for each field are assigned so that a bootstrap class of 'form-control' could be added     to each widget. The date_of_birth field's input format is set as MM/DD/YYYY in the widget. # return email A custom form used by UserProfileUpdateView to allow authenticated users to update their profile     information. Widgets for each field are assigned so that a bootstrap class of 'form-control'     could be added to each widget. The date_of_birth field's input format is set as MM/DD/YYYY in the widget. #Copied from SetPasswordForm A form that lets a user change set their password without entering the old     password. This was copied over from SetPasswordForm, which is used by the class_form = PasswordChangeForm that is used     by the generic PasswordChangeView. This was copied over so that the bootstrap class 'form-control' could be added     to each widget to allow for bootstrap styling. #Copied from PasswordChangeForm A form that lets a user change their password by entering their old     password. This was copied from the PasswordChangeForm, which is the class_form for the generic     PasswordChangeView. This was copied over so that the bootstrap class 'form-control' could be added     to each widget to allow for bootstrap styling. Validate that the old_password field is correct. Send a django.core.mail.EmailMultiAlternatives to `to_email`. # Email subject *must not* contain newlines Given an email, return matching user(s) who should receive a reset.          This allows subclasses to more easily customize the default policies         that prevent inactive users and users with unusable passwords from         resetting their password. Generate a one-use only link for resetting password and send it to the         user. A form that lets a user change set their password without entering the old     password # help_text=password_validation.password_validators_help_text_html(),