# -*- coding: utf-8 -*-
import datetime
from dateutil.relativedelta import relativedelta
from django.http import HttpResponse
from django.db.models import Q
from coin.offers.models import Offer, OfferSubscription
from coin.members.models import Member
from coin.billing.models import Invoice, InvoiceDetail



def create_all_members_invoices_for_a_period(date):
    """
    Pour chaque membre ayant au moins un abonnement actif, génère les factures
    en prenant la date comme premier mois de la période de facturation
    """
    members = Member.objects.filter(
        Q(offersubscription__resign_date__isnull=True) |
        Q(offersubscription__resign_date__gte=datetime.date.today()))

    for member in members:
        create_member_invoice_for_a_period(member,date)


def create_member_invoice_for_a_period(member, date):
    """
    Créé si necessaire une facture pour un membre en prenant la date passée
    en paramètre comme premier mois de période. Renvoi la facture générée
    ou None si aucune facture n'était pas necessaire.
    """
    invoice = None

    # Récupère les abonnements en cours du membre
    offer_subscriptions = member.get_active_subscriptions(date)

    # Pour chaque abonnement
    for offer_subscription in offer_subscriptions:
        # Récupère l'offre de l'abonnement
        offer = offer_subscription.offer

        # Recherche dans les factures déjà existantes de ce membre des items
        # ayant cet abonnement pour lesquels la période de facturation englobe
        # la date
        invoicedetail_test_before = InvoiceDetail.objects.filter(
            offersubscription__exact=offer_subscription.pk,
            period_from__lte=date,
            period_to__gte=date,
            invoice__member__exact=member.pk)

        # Si une telle facture n'existe pas, alors ajout l'item à facturer à la
        # facture à générer
        if not invoicedetail_test_before.exists():
            # Si l'object facture n'a pas encore été créé, le créé
            if invoice is None:
                invoice = Invoice.objects.create(
                    date_due=datetime.date.today(),
                    member=member
                )

            # Vérifie s'il s'agit de la première facture d'un abonnement,
            # Alors facture en plus les frais de mise en service
            invoicedetail_test_first = InvoiceDetail.objects.filter(
                offersubscription__exact=offer_subscription.pk,
                invoice__member__exact=member.pk)
            if not invoicedetail_test_first.exists():
                invoice.details.create(
                    label=offer.name + " - Frais de mise en service",
                    amount=offer.initial_fees,
                    offersubscription=offer_subscription,
                    period_from=None,
                    period_to=None)

            # Période de facturation de l'item par defaut
            # - Du début du mois de la date passée en paramètre
            # - Jusqu'à la fin du mois de la période de facturation de l'offre
            period_from = datetime.date(date.year, date.month, 1)
            period_to = (datetime.date(date.year, date.month, 1) +
                         relativedelta(months=+offer.billing_period) -
                         relativedelta(days=+1))

            # Recherche dans les factures déjà existantes de ce membre des
            # items ayant cet abonnement pour lesquels la période de
            # facturation commence avant la fin de notre période de facturation
            # actuelle
            invoicedetail_test_after = InvoiceDetail.objects.filter(
                offersubscription__exact=offer_subscription.pk,
                period_from__lte=period_to,
                period_from__gte=period_from,
                invoice__member__exact=member.pk)

            # Si une telle facture existe, récupère la date de début de
            # facturation pour en faire la date de fin de facturation
            if invoicedetail_test_after.exists():
                invoicedetail_after = invoicedetail_test_after.first()
                period_to = (
                    datetime.date(invoicedetail_after.period_from.year,
                                  invoicedetail_after.period_from.month, 1) -
                    relativedelta(days=+1))

            # Ajout l'item de l'offre correspondant à l'abonnement à la facture
            invoice.details.create(label=offer.name,
                                   amount=offer.period_fees,
                                   offersubscription=offer_subscription,
                                   period_from=period_from,
                                   period_to=period_to)

            invoice.save()

    return invoice
