# -*- coding: utf-8 -*-
from __future__ import unicode_literals

import datetime
import random
import uuid
import os
from decimal import Decimal

from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver

from coin.offers.models import OfferSubscription
from coin.members.models import Member
from coin.html2pdf import render_as_pdf
from coin.utils import private_files_storage, start_of_month, end_of_month


def next_invoice_number():
    """Détermine un numéro de facture aléatoire"""
    return '%s%02i-%i-%i' % (datetime.date.today().year,
                              datetime.date.today().month,
                              random.randrange(100, 999),
                              random.randrange(100, 999))

def invoice_pdf_filename(instance, filename):
    """Nom du fichier pdf à stocker pour les factures"""
    return 'invoices/%d_%s_%s.pdf' % (getattr(instance,'member.id',0), instance.number, uuid.uuid4())

class Invoice(models.Model):

    INVOICES_STATUS_CHOICES = (
        ('open', 'A payer'),
        ('closed', 'Reglée'),
        ('trouble', 'Litige')
    )

    validated = models.BooleanField(default=False, verbose_name='validée')
    number = models.CharField(max_length=25,
                              default=next_invoice_number,
                              unique=True,
                              verbose_name='numéro')
    status = models.CharField(max_length=50, choices=INVOICES_STATUS_CHOICES,
                              default='open',
                              verbose_name='statut')
    date = models.DateField(default=datetime.date.today, null=True, verbose_name='date')
    date_due = models.DateField(
        default=end_of_month,
        null=True,
        verbose_name="date d'échéance de paiement")
    member = models.ForeignKey(Member, null=True, blank=True, default=None,
                               related_name='invoices',
                               verbose_name='membre',
                               on_delete=models.SET_NULL)
    pdf = models.FileField(storage=private_files_storage, upload_to=invoice_pdf_filename,
                           null=True, blank=True,
                           verbose_name='PDF')

    def amount(self):
        """Calcul le montant de la facture en fonction des éléments de détails"""
        total = Decimal('0.0')
        for detail in self.details.all():
            total += detail.total()
        return total.quantize(Decimal('0.01'))
    amount.short_description = 'Montant'

    def amount_paid(self):
        """
        Calcul le montant payé de la facture en fonction des éléments
        de paiements
        """
        total = Decimal('0.0')
        for payment in self.payments.all():
            total += payment.amount
        return total.quantize(Decimal('0.01'))
    amount_paid.short_description = 'Montant payé'

    def amount_remaining_to_pay(self):
        """
        Calcul le montant restant à payer
        """
        return self.amount() - self.amount_paid()
    amount_remaining_to_pay.short_description = 'Reste à payer'

    def has_owner(self, username):
        "Check if passed username (ex gmajax) is owner of the invoice"
        return (self.member.username == username)

    def generate_pdf(self):
        "Make and store a pdf file for the invoice"
        pdf_file = render_as_pdf('billing/invoice_pdf.html', {"invoice": self})
        self.pdf.save('%s.pdf' % self.number, pdf_file)

    def validate(self):
        """
        Switch invoice to validate mode. This set to False the draft field
        and generate the pdf
        """
        if not self.is_pdf_exists():
            self.validated = True
            self.save()
            self.generate_pdf()

    def is_pdf_exists(self):
        return self.validated and bool(self.pdf) and private_files_storage.exists(self.pdf.name)

    def __unicode__(self):
        return '#%s %0.2f€ %s' % (self.number, self.amount(), self.date_due)

    class Meta:
        verbose_name = 'facture'


class InvoiceDetail(models.Model):

    label = models.CharField(max_length=100)
    amount = models.DecimalField(max_digits=5, decimal_places=2,
                                 verbose_name='montant')
    quantity = models.DecimalField(null=True, verbose_name='quantité',
                                   default=1.0, decimal_places=2, max_digits=4)
    tax = models.DecimalField(null=True, default=0.0, decimal_places=2,
                              max_digits=4, verbose_name='TVA',
                              help_text='en %')
    invoice = models.ForeignKey(Invoice, verbose_name='facture',
                                related_name='details')
    offersubscription = models.ForeignKey(OfferSubscription, null=True,
                                          blank=True, default=None,
                                          verbose_name='abonnement')
    period_from = models.DateField(
        default=start_of_month,
        null=True,
        blank=True,
        verbose_name='début de période',
        help_text='Date de début de période sur laquelle est facturé cet item')
    period_to = models.DateField(
        default=end_of_month,
        null=True,
        blank=True,
        verbose_name='fin de période',
        help_text='Date de fin de période sur laquelle est facturé cet item')

    def __unicode__(self):
        return self.label

    def total(self):
        """Calcul le total"""
        return (self.amount * (self.tax / Decimal('100.0') +
                Decimal('1.0')) * self.quantity).quantize(Decimal('0.01'))

    class Meta:
        verbose_name = 'détail de facture'


class Payment(models.Model):

    PAYMENT_MEAN_CHOICES = (
        ('cash', 'Espèces'),
        ('check', 'Chèque'),
        ('transfer', 'Virement'),
        ('other', 'Autre')
    )

    payment_mean = models.CharField(max_length=100, null=True,
                                    default='transfer',
                                    choices=PAYMENT_MEAN_CHOICES,
                                    verbose_name='moyen de paiement')
    amount = models.DecimalField(max_digits=5, decimal_places=2, null=True,
                                 verbose_name='montant')
    date = models.DateField(default=datetime.date.today)
    invoice = models.ForeignKey(Invoice, verbose_name='facture',
                                related_name='payments')

    def __unicode__(self):
        return 'Paiment de %0.2f€' % self.amount

    class Meta:
        verbose_name = 'paiement'

@receiver(post_save, sender=Payment)
def set_invoice_as_paid_if_needed(sender, instance, **kwargs):
    """
    Lorsqu'un paiement est enregistré, vérifie si la facture est alors
    complétement payée. Dans ce cas elle passe en réglée
    """
    if (instance.invoice.amount_paid >= instance.invoice.amount and
       instance.invoice.status == 'open'):
       instance.invoice.status = 'closed'
       instance.invoice.save()

