import re

from django import forms
from django.contrib.auth import get_user_model, password_validation
from django.utils.safestring import mark_safe

from .backends import normalize_phone
from .models import CustomerProfile

User = get_user_model()
TERMS_LABEL = mark_safe('আমি <a href="/terms-and-conditions/" target="_blank" rel="noopener">শর্তাবলী</a> ও '
                        '<a href="/privacy-policy/" target="_blank" rel="noopener">গোপনীয়তা নীতি</a> মেনে নিচ্ছি')
TERMS_REQUIRED = 'অ্যাকাউন্ট ব্যবহার করতে শর্তাবলী ও গোপনীয়তা নীতি মেনে নিতে হবে।'


def terms_field():
    return forms.BooleanField(required=True, initial=True, label=TERMS_LABEL,
                              error_messages={'required': TERMS_REQUIRED})


BD_PHONE_RE = re.compile(r'^01[3-9]\d{8}$')


def clean_phone_value(value, exclude_user=None):
    phone = normalize_phone(value)
    if not phone:
        return None
    if not BD_PHONE_RE.match(phone):
        raise forms.ValidationError('Enter a valid Bangladeshi mobile number, e.g. 01712345678.')
    taken = CustomerProfile.objects.filter(phone=phone)
    if exclude_user is not None:
        taken = taken.exclude(user=exclude_user)
    if taken.exists():
        raise forms.ValidationError('An account already uses this mobile number. Try signing in.')
    return phone


class SignupForm(forms.Form):
    name = forms.CharField(max_length=150, label='Full name',
                           widget=forms.TextInput(attrs={'autocomplete': 'name'}))
    email = forms.EmailField(label='Email',
                             widget=forms.EmailInput(attrs={'autocomplete': 'email'}))
    phone = forms.CharField(max_length=20, required=False, label='Mobile number (optional)',
                            help_text='Lets you sign in with your phone and links your magazine purchases.',
                            widget=forms.TextInput(attrs={'autocomplete': 'tel', 'inputmode': 'tel', 'placeholder': '01XXXXXXXXX'}))
    password1 = forms.CharField(label='Password', strip=False,
                                widget=forms.PasswordInput(attrs={'autocomplete': 'new-password'}),
                                help_text='At least 8 characters. Avoid common words.')
    password2 = forms.CharField(label='Confirm password', strip=False,
                                widget=forms.PasswordInput(attrs={'autocomplete': 'new-password'}))
    wants_newsletter = forms.BooleanField(required=False, initial=True,
                                          label='Email me new articles and magazine issues')
    accept_terms = terms_field()

    def clean_email(self):
        email = self.cleaned_data['email'].strip().lower()
        if User.objects.filter(email__iexact=email).exists():
            raise forms.ValidationError('An account with this email already exists. Try signing in.')
        return email

    def clean_phone(self):
        return clean_phone_value(self.cleaned_data.get('phone'))

    def clean(self):
        data = super().clean()
        p1, p2 = data.get('password1'), data.get('password2')
        if p1 and p2 and p1 != p2:
            self.add_error('password2', 'The two passwords don’t match.')
        elif p1:
            temp = User(username=data.get('email', ''), email=data.get('email', ''), first_name=data.get('name', ''))
            try:
                password_validation.validate_password(p1, temp)
            except forms.ValidationError as exc:
                self.add_error('password1', exc)
        return data

    def save(self):
        d = self.cleaned_data
        parts = d['name'].strip().split(' ', 1)
        user = User.objects.create_user(username=d['email'][:150], email=d['email'], password=d['password1'],
                                        first_name=parts[0][:150], last_name=(parts[1] if len(parts) > 1 else '')[:150])
        profile = user.profile
        profile.phone = d['phone']
        profile.wants_newsletter = d['wants_newsletter']
        from django.utils import timezone
        profile.terms_accepted_at = timezone.now()
        profile.save()
        return user


class LoginForm(forms.Form):
    identifier = forms.CharField(max_length=254, label='Email or mobile number',
                                 widget=forms.TextInput(attrs={'autocomplete': 'username', 'autofocus': True}))
    password = forms.CharField(label='Password', strip=False,
                               widget=forms.PasswordInput(attrs={'autocomplete': 'current-password'}))
    remember = forms.BooleanField(required=False, initial=True, label='Keep me signed in')
    accept_terms = terms_field()


class ProfileForm(forms.Form):
    name = forms.CharField(max_length=150, label='Full name')
    phone = forms.CharField(max_length=20, required=False, label='Mobile number',
                            widget=forms.TextInput(attrs={'inputmode': 'tel', 'placeholder': '01XXXXXXXXX'}))
    alt_phone = forms.CharField(max_length=20, required=False, label='Alternative mobile (optional)',
                                widget=forms.TextInput(attrs={'inputmode': 'tel', 'placeholder': '01XXXXXXXXX',
                                                              'autocomplete': 'tel'}))
    division = forms.CharField(max_length=40, required=False, label='Division / বিভাগ')
    district = forms.CharField(max_length=40, required=False, label='District / জেলা')
    area = forms.CharField(max_length=80, required=False, label='Area / Upazila / Thana — এলাকা / উপজেলা / থানা')
    address = forms.CharField(required=False, max_length=300, label='Village / Road / House / Market — গ্রাম / রোড / বাসা / মার্কেট',
                              widget=forms.Textarea(attrs={'rows': 2, 'autocomplete': 'street-address',
                                                           'placeholder': 'যেমন: বাসা ১২, রোড ৫, ব্লক সি'}))
    wants_newsletter = forms.BooleanField(required=False, label='Email me new articles and magazine issues')

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

    def clean_phone(self):
        return clean_phone_value(self.cleaned_data.get('phone'), exclude_user=self.user)

    def clean_alt_phone(self):
        phone = normalize_phone(self.cleaned_data.get('alt_phone'))
        if phone and not BD_PHONE_RE.match(phone):
            raise forms.ValidationError('Enter a valid Bangladeshi mobile number, e.g. 01712345678.')
        return phone

    def clean(self):
        from .locations import is_valid
        d = super().clean()
        picked = [d.get('division'), d.get('district'), d.get('area')]
        if any(picked) and not is_valid(*picked):
            self.add_error('area', 'Please choose your division, district and area from the lists.')
        return d


class ClaimForm(forms.Form):
    phone = forms.CharField(max_length=20, label='Mobile number used for the purchase')
    code = forms.CharField(max_length=30, label='Transaction ID, reference (RT-…) or order number')
