# -*- coding: utf-8 -*-

from __future__ import (absolute_import, division,
                        print_function, unicode_literals)
from builtins import *

from decimal import Decimal
from django import forms
from django.core.exceptions import ValidationError
from django.core.validators import MinLengthValidator
from django.contrib.auth.models import User, Group, Permission
from django.contrib.contenttypes.models import ContentType
from django.forms import modelformset_factory, inlineformset_factory
from django.forms.models import BaseInlineFormSet
from django.utils import timezone
from kfet.models import (Account, Checkout, Article, OperationGroup, Operation,
    CheckoutStatement, ArticleCategory, Settings, AccountNegative, Transfer,
    TransferGroup, Supplier, Inventory, InventoryArticle)
from gestioncof.models import CofProfile

# -----
# Widgets
# -----

class DateTimeWidget(forms.DateTimeInput):
    def __init__(self, attrs = None):
        super(DateTimeWidget, self).__init__(attrs)
        self.attrs['format'] = '%Y-%m-%d %H:%M'
    class Media:
        css = {
                'all': ('kfet/css/bootstrap-datetimepicker.min.css',)
            }
        js  = (
                'kfet/js/moment.js',
                'kfet/js/moment-fr.js',
                'kfet/js/bootstrap-datetimepicker.min.js',
            )
# -----
# Account forms
# -----

class AccountForm(forms.ModelForm):

    # Surcharge pour passer data à Account.save()
    def save(self, data = {}, *args, **kwargs):
        obj = super(AccountForm, self).save(commit = False, *args, **kwargs)
        obj.save(data = data)
        return obj

    class Meta:
        model  = Account
        fields = ['trigramme', 'promo', 'nickname', 'is_frozen']
        widgets = {
            'trigramme': forms.TextInput(attrs={'autocomplete': 'off'}),
        }

class AccountBalanceForm(forms.ModelForm):
    class Meta:
        model = Account
        fields = ['balance']

class AccountTriForm(AccountForm):

    def clean_trigramme(self):
        trigramme = self.cleaned_data['trigramme']
        return trigramme.upper()

    class Meta(AccountForm.Meta):
        fields = ['trigramme']

class AccountNoTriForm(AccountForm):
    class Meta(AccountForm.Meta):
        exclude = ['trigramme']

class AccountRestrictForm(AccountForm):
    class Meta(AccountForm.Meta):
        fields = ['is_frozen']

class AccountPwdForm(forms.Form):
    pwd1 = forms.CharField(
            widget=forms.PasswordInput)
    pwd2 = forms.CharField(
            widget=forms.PasswordInput)

    def clean(self):
        pwd1 = self.cleaned_data.get('pwd1', '')
        pwd2 = self.cleaned_data.get('pwd2', '')
        if len(pwd1) < 8:
            raise ValidationError("Mot de passe trop court")
        if pwd1 != pwd2:
            raise ValidationError("Les mots de passes sont différents")
        super(AccountPwdForm, self).clean()

class CofForm(forms.ModelForm):
    def clean_is_cof(self):
        instance = getattr(self, 'instance', None)
        if instance and instance.pk:
            return instance.is_cof
        else:
            return False
    class Meta:
        model  = CofProfile
        fields = ['login_clipper', 'is_cof', 'departement']

class CofRestrictForm(CofForm):
    class Meta(CofForm.Meta):
        fields = ['departement']

class UserForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        from_clipper = kwargs.pop('from_clipper', False)
        new_user = kwargs.get('instance') is None and not from_clipper
        super(UserForm, self).__init__(*args, **kwargs)
        if new_user:
            self.fields['username'].validators = [MinLengthValidator(9)]

    class Meta:
        model  = User
        fields = ['username', 'first_name', 'last_name', 'email']
        help_texts = {
            'username': ''
        }

class UserRestrictForm(UserForm):
    class Meta(UserForm.Meta):
        fields = ['first_name', 'last_name']

class UserRestrictTeamForm(UserForm):
    class Meta(UserForm.Meta):
        fields = ['first_name', 'last_name', 'email']

class UserGroupForm(forms.ModelForm):
    groups = forms.ModelMultipleChoiceField(
            Group.objects.filter(name__icontains='K-Fêt'))
    class Meta:
        model  = User
        fields = ['groups']

class GroupForm(forms.ModelForm):
    permissions = forms.ModelMultipleChoiceField(
        queryset= Permission.objects.filter(content_type__in=
            ContentType.objects.filter(app_label='kfet')))

    def clean_name(self):
        name = self.cleaned_data['name']
        return 'K-Fêt %s' % name

    class Meta:
        model  = Group
        fields = ['name', 'permissions']

class AccountNegativeForm(forms.ModelForm):
    class Meta:
        model  = AccountNegative
        fields = ['authz_overdraft_amount', 'authz_overdraft_until',
                  'balance_offset', 'comment']
        widgets = {
            'authz_overdraft_until': DateTimeWidget(),
        }

# -----
# Checkout forms
# -----

class CheckoutForm(forms.ModelForm):
    class Meta:
        model   = Checkout
        fields  = ['name', 'valid_from', 'valid_to', 'balance', 'is_protected']
        widgets = {
            'valid_from': DateTimeWidget(),
            'valid_to'  : DateTimeWidget(),
        }

class CheckoutRestrictForm(CheckoutForm):
    class Meta(CheckoutForm.Meta):
        fields = ['name', 'valid_from', 'valid_to']


class CheckoutStatementCreateForm(forms.ModelForm):
    balance_001 = forms.IntegerField(min_value=0, initial=0, required=False)
    balance_002 = forms.IntegerField(min_value=0, initial=0, required=False)
    balance_005 = forms.IntegerField(min_value=0, initial=0, required=False)
    balance_01 = forms.IntegerField(min_value=0, initial=0, required=False)
    balance_02 = forms.IntegerField(min_value=0, initial=0, required=False)
    balance_05 = forms.IntegerField(min_value=0, initial=0, required=False)
    balance_1 = forms.IntegerField(min_value=0, initial=0, required=False)
    balance_2 = forms.IntegerField(min_value=0, initial=0, required=False)
    balance_5 = forms.IntegerField(min_value=0, initial=0, required=False)
    balance_10 = forms.IntegerField(min_value=0, initial=0, required=False)
    balance_20 = forms.IntegerField(min_value=0, initial=0, required=False)
    balance_50 = forms.IntegerField(min_value=0, initial=0, required=False)
    balance_100 = forms.IntegerField(min_value=0, initial=0, required=False)
    balance_200 = forms.IntegerField(min_value=0, initial=0, required=False)
    balance_500 = forms.IntegerField(min_value=0, initial=0, required=False)

    class Meta:
        model = CheckoutStatement
        exclude = ['by', 'at', 'checkout', 'amount_error', 'amount_taken',
                   'balance_old', 'balance_new']

    def clean(self):
        not_count = self.cleaned_data['not_count']
        if not not_count and (
                self.cleaned_data['balance_001'] is None
                or self.cleaned_data['balance_002'] is None
                or self.cleaned_data['balance_005'] is None
                or self.cleaned_data['balance_01'] is None
                or self.cleaned_data['balance_02'] is None
                or self.cleaned_data['balance_05'] is None
                or self.cleaned_data['balance_1'] is None
                or self.cleaned_data['balance_2'] is None
                or self.cleaned_data['balance_5'] is None
                or self.cleaned_data['balance_10'] is None
                or self.cleaned_data['balance_20'] is None
                or self.cleaned_data['balance_50'] is None
                or self.cleaned_data['balance_100'] is None
                or self.cleaned_data['balance_200'] is None
                or self.cleaned_data['balance_500'] is None):
            raise ValidationError("Y'a un problème. Si tu comptes la caisse, mets au moins des 0 stp (et t'as pas idée de comment c'est long de vérifier que t'as mis des valeurs de partout...)")
        super(CheckoutStatementCreateForm, self).clean()

class CheckoutStatementUpdateForm(forms.ModelForm):
    class Meta:
        model = CheckoutStatement
        exclude = ['by', 'at', 'checkout', 'amount_error', 'amount_taken']

# -----
# Article forms
# -----

class ArticleForm(forms.ModelForm):
    category_new = forms.CharField(
            max_length=45,
            required = False)
    category = forms.ModelChoiceField(
            queryset = ArticleCategory.objects.all(),
            required = False)

    suppliers = forms.ModelMultipleChoiceField(
            queryset = Supplier.objects.all(),
            required = False)
    supplier_new = forms.CharField(
            max_length = 45,
            required   = False)

    def __init__(self, *args, **kwargs):
        super(ArticleForm, self).__init__(*args, **kwargs)
        if self.instance.pk:
            self.initial['suppliers'] = self.instance.suppliers.values_list('pk', flat=True)

    def clean(self):
        category     = self.cleaned_data.get('category')
        category_new = self.cleaned_data.get('category_new')

        if not category and not category_new:
            raise ValidationError('Sélectionnez une catégorie ou créez en une')
        elif not category:
            category, _ = ArticleCategory.objects.get_or_create(name=category_new)
            self.cleaned_data['category'] = category

        super(ArticleForm, self).clean()

    class Meta:
        model  = Article
        fields = ['name', 'is_sold', 'price', 'stock', 'category', 'box_type',
                  'box_capacity']

class ArticleRestrictForm(ArticleForm):
    class Meta(ArticleForm.Meta):
        fields = ['name', 'is_sold', 'price', 'category', 'box_type',
                  'box_capacity']

# -----
# K-Psul forms
# -----

class KPsulOperationGroupForm(forms.ModelForm):
    checkout = forms.ModelChoiceField(
        queryset = Checkout.objects.filter(
            is_protected=False, valid_from__lte=timezone.now(),
            valid_to__gte=timezone.now()),
        widget   = forms.HiddenInput())
    on_acc = forms.ModelChoiceField(
        queryset = Account.objects.exclude(trigramme='GNR'),
        widget = forms.HiddenInput())
    class Meta:
        model  = OperationGroup
        fields = ['on_acc', 'checkout', 'comment']

class KPsulAccountForm(forms.ModelForm):
    class Meta:
        model   = Account
        fields  = ['trigramme']
        widgets = {
            'trigramme': forms.TextInput(
                attrs={
                    'autocomplete': 'off',
                    'spellcheck': 'false',
                }),
        }

class KPsulCheckoutForm(forms.Form):
    checkout = forms.ModelChoiceField(
            queryset=Checkout.objects.filter(
            is_protected=False, valid_from__lte=timezone.now(),
            valid_to__gte=timezone.now()),
            widget=forms.Select(attrs={'id':'id_checkout_select'}))

class KPsulOperationForm(forms.ModelForm):
    article = forms.ModelChoiceField(
        queryset=Article.objects.select_related('category').all(),
        required=False,
        widget  = forms.HiddenInput())
    class Meta:
        model  = Operation
        fields = ['type', 'amount', 'is_checkout', 'article', 'article_nb']
        widgets = {
            'type': forms.HiddenInput(),
            'amount': forms.HiddenInput(),
            'is_checkout': forms.HiddenInput(),
            'article_nb': forms.HiddenInput(),
        }

    def clean(self):
        super(KPsulOperationForm, self).clean()
        type_ope   = self.cleaned_data.get('type')
        amount     = self.cleaned_data.get('amount')
        article    = self.cleaned_data.get('article')
        article_nb = self.cleaned_data.get('article_nb')
        if type_ope and type_ope == Operation.PURCHASE:
            if not article or not article_nb:
                raise ValidationError(
                    "Un achat nécessite un article et une quantité")
            if article_nb < 1:
                raise ValidationError("Impossible d'acheter moins de 1 article")
            self.cleaned_data['is_checkout'] = True
        elif type_ope and type_ope in [Operation.DEPOSIT, Operation.WITHDRAW]:
            if not amount or article or article_nb:
                raise ValidationError("Bad request")
            if type_ope == Operation.DEPOSIT and amount <= 0:
                raise ValidationError("Charge non positive")
            if type_ope == Operation.WITHDRAW and amount >= 0:
                raise ValidationError("Retrait non négatif")
            self.cleaned_data['article']    = None
            self.cleaned_data['article_nb'] = None

KPsulOperationFormSet = modelformset_factory(
    Operation,
    form    = KPsulOperationForm,
    can_delete = True,
    extra   = 0,
    min_num = 1, validate_min = True)

class AddcostForm(forms.Form):
    trigramme = forms.CharField(required = False)
    amount = forms.DecimalField(
        required = False,
        max_digits=6,decimal_places=2,min_value=Decimal(0))

    def clean(self):
        trigramme = self.cleaned_data.get('trigramme')
        if trigramme:
            try:
                Account.objects.get(trigramme=trigramme)
            except Account.DoesNotExist:
                raise ValidationError('Compte invalide')
        else:
            self.cleaned_data['amount'] = 0
        super(AddcostForm, self).clean()

# -----
# Settings forms
# -----

class SettingsForm(forms.ModelForm):
    class Meta:
        model  = Settings
        fields = ['value_decimal', 'value_account', 'value_duration']

    def clean(self):
        name = self.instance.name
        value_decimal = self.cleaned_data.get('value_decimal')
        value_account = self.cleaned_data.get('value_account')
        value_duration = self.cleaned_data.get('value_duration')

        type_decimal = ['SUBVENTION_COF', 'ADDCOST_AMOUNT', 'OVERDRAFT_AMOUNT']
        type_account = ['ADDCOST_FOR']
        type_duration = ['OVERDRAFT_DURATION', 'CANCEL_DURATION']

        self.cleaned_data['name'] = name
        if name in type_decimal:
            if not value_decimal:
                raise ValidationError('Renseignez une valeur décimale')
            self.cleaned_data['value_account'] = None
            self.cleaned_data['value_duration'] = None
        elif name in type_account:
            self.cleaned_data['value_decimal'] = None
            self.cleaned_data['value_duration'] = None
        elif name in type_duration:
            if not value_duration:
                raise ValidationError('Renseignez une durée')
            self.cleaned_data['value_decimal'] = None
            self.cleaned_data['value_account'] = None
        super(SettingsForm, self).clean()

class FilterHistoryForm(forms.Form):
    checkouts = forms.ModelMultipleChoiceField(queryset = Checkout.objects.all())
    accounts = forms.ModelMultipleChoiceField(queryset = Account.objects.all())

# -----
# Transfer forms
# -----

class TransferGroupForm(forms.ModelForm):
    class Meta:
        model  = TransferGroup
        fields = ['comment']

class TransferForm(forms.ModelForm):
    from_acc = forms.ModelChoiceField(
        queryset = Account.objects.exclude(trigramme__in=['LIQ', '#13', 'GNR']),
        widget   = forms.HiddenInput()
    )
    to_acc = forms.ModelChoiceField(
        queryset = Account.objects.exclude(trigramme__in=['LIQ', '#13', 'GNR']),
        widget   = forms.HiddenInput()
    )

    def clean_amount(self):
        amount = self.cleaned_data['amount']
        if amount <= 0:
            raise forms.ValidationError("Montant invalide")
        return amount

    class Meta:
        model  = Transfer
        fields = ['from_acc', 'to_acc', 'amount']

TransferFormSet = modelformset_factory(
    Transfer,
    form = TransferForm,
    min_num = 1, validate_min = True,
    extra = 9,
)

# -----
# Inventory forms
# -----

class InventoryArticleForm(forms.Form):
    article = forms.ModelChoiceField(
            queryset = Article.objects.all(),
            widget = forms.HiddenInput(),
        )
    stock_new = forms.IntegerField(required = False)

    def __init__(self, *args, **kwargs):
        super(InventoryArticleForm, self).__init__(*args, **kwargs)
        if 'initial' in kwargs:
            self.name      = kwargs['initial']['name']
            self.stock_old = kwargs['initial']['stock_old']
            self.category  = kwargs['initial']['category']
            self.category_name = kwargs['initial']['category__name']

# -----
# Order forms
# -----

class OrderArticleForm(forms.Form):
    article = forms.ModelChoiceField(
            queryset = Article.objects.all(),
            widget = forms.HiddenInput(),
        )
    quantity_ordered = forms.IntegerField(required = False)

    def __init__(self, *args, **kwargs):
        super(OrderArticleForm, self).__init__(*args, **kwargs)
        if 'initial' in kwargs:
            self.name = kwargs['initial']['name']
            self.stock = kwargs['initial']['stock']
            self.category = kwargs['initial']['category']
            self.category_name = kwargs['initial']['category__name']
            self.box_capacity = kwargs['initial']['box_capacity']
            self.v_s1 = kwargs['initial']['v_s1']
            self.v_s2 = kwargs['initial']['v_s2']
            self.v_s3 = kwargs['initial']['v_s3']
            self.v_s4 = kwargs['initial']['v_s4']
            self.v_s5 = kwargs['initial']['v_s5']
            self.v_moy = kwargs['initial']['v_moy']
            self.v_et = kwargs['initial']['v_et']
            self.v_prev = kwargs['initial']['v_prev']
            self.c_rec = kwargs['initial']['c_rec']

class OrderArticleToInventoryForm(forms.Form):
    article = forms.ModelChoiceField(
            queryset = Article.objects.all(),
            widget = forms.HiddenInput(),
        )
    price_HT = forms.DecimalField(
            max_digits = 7, decimal_places = 4,
            required = False)
    TVA = forms.DecimalField(
            max_digits = 7, decimal_places = 2,
            required = False)
    rights = forms.DecimalField(
            max_digits = 7, decimal_places = 4,
            required = False)
    quantity_received = forms.IntegerField()

    def __init__(self, *args, **kwargs):
        super(OrderArticleToInventoryForm, self).__init__(*args, **kwargs)
        if 'initial' in kwargs:
            self.name = kwargs['initial']['name']
            self.category = kwargs['initial']['category']
            self.category_name = kwargs['initial']['category__name']
            self.quantity_ordered = kwargs['initial']['quantity_ordered']