# -*- coding: utf-8 -*-
#!/usr/bin/env python

"""
Script de contrôle et de reporting
"""

import os
import tempfile

from datetime import datetime, timedelta
from datetime import date as date_setter

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "calebasse.settings")

from calebasse.facturation.models import Invoice
from calebasse.actes.models import Act, ValidationMessage
from calebasse.dossiers.models import PatientRecord
from calebasse.agenda.models import EventWithAct

SEND_MAIL = "mates@entrouvert.com"
OUTPUT_DIR = "/var/log/calebasse"
PREFIX = "analyse"

ANALYSE_SDT = datetime(2013,1,1)

ALWAYS_SEND_MAIL = True

LOOKUP_NEW = True
END_LOOKUP = datetime.today()

SERVICES = ('CMPP', 'CAMSP', 'SESSAD TED', 'SESSAD DYS')
#SERVICES = ('CAMSP',)
#SERVICES = ('CAMSP', 'SESSAD TED', 'SESSAD DYS')
#SERVICES = ('SESSAD DYS',)

QUIET = False

if __name__ == '__main__' :
    prefix = '%s-%s.' % (PREFIX, datetime.utcnow())
    logger_fn = os.path.join(OUTPUT_DIR, prefix + 'log')
    assert not os.path.isfile(logger_fn), 'Analyse log file "%s" already exists' % logger_fn
    logger = tempfile.NamedTemporaryFile(suffix='.logtmp',
            prefix=prefix, dir=OUTPUT_DIR, delete=False)

    logger.write("Script de contôle de Calebasse : %s\n\n" % datetime.utcnow())

    need_mail = False

    if LOOKUP_NEW:
        for service_name in SERVICES:
            for date in [(ANALYSE_SDT + timedelta(days=i)).date() for i in range(0, (END_LOOKUP.date()-ANALYSE_SDT.date()).days)]:
                "Be sure all acts are created in 2014"
                acts = list(Act.objects \
                        .filter(date=date, patient__service__name=service_name) \
                        .select_related() \
                        .prefetch_related('doctors',
                                'patient__patientcontact',
                                'actvalidationstate_set__previous_state') \
                        .order_by('time'))
                event_ids = [ a.parent_event_id for a in acts if a.parent_event_id ]
                events = EventWithAct.objects.for_today(date) \
                        .filter(patient__service__name=service_name) \
                        .exclude(id__in=event_ids)
                events = [ event.today_occurrence(date) for event in events ]
                acts += [ event.act for event in events if event ]
                for act in acts:
                    if not act.id:
                        act.save()

    logger.write("Traitement des données\n")
    logger.write("----------------------\n\n")
    invoices = {'CMPP' : {}, 'CAMSP' : {}, 'SESSAD TED' : {}, 'SESSAD DYS' : {}}
    for invoice in Invoice.objects.all():
        try:
            patient = PatientRecord.objects.get(id=invoice.patient_id)
            invoices[patient.service.name].setdefault(invoice.invoicing, []).append(invoice)
        except:
            if invoice.patient_id:
                need_mail = True
                logger.write("$$$ La facture %d (%d, %d) a pour id patient %d qui n'existe pas\n" % (invoice.id, invoice.batch, invoice.number, invoice.patient_id))
            else:
                logger.write("La facture %d n'a pas de patient\n" % invoice.id)
            if len(invoice.list_dates.split('$')) > invoice.acts.all().count():
                logger.write("Cette facture présente des actes manquants\n")
    logger.write("Traitement terminé\n\n")

    for service_name in SERVICES:
        service_str = "Service : %s" % service_name
        logger.write('='+'='.join(['' for c in service_str])+"\n")
        logger.write(service_str+"\n")
        logger.write('='+'='.join(['' for c in service_str])+"\n\n")

        acts = Act.objects.filter(date__gte=ANALYSE_SDT.date(), patient__service__name=service_name)

        logger.write("Vérifications Event canceled avec des actes already_billed\n")
        logger.write("---------------------------------------------------------\n\n")
        r_list = []
        for id in set([a.parent_event.id for a in Act.objects.filter(parent_event__canceled = True, already_billed = True)]):
            e = EventWithAct.objects.get(id=id)
            if e.is_recurring():
                logger.write("Recurrent : %d\n" % e.id)
                r_list.append(id)
            elif e.exception_to:
                logger.write("Exception %d au recurrent : %d\n" % (e.id, e.exception_to.id))
                if not e.exception_to.canceled:
                    logger.write("\tLe récurrent n'est pas canceled, we can fix easily setting this exception not canceled\n")
            else:
                logger.write("Simple : %d, we can fix easily setting this exception not canceled\n" % e.id)

        logger.write("\n")

        logger.write("Vérifications des pointages et vérouillages des actes\n")
        logger.write("-----------------------------------------------------\n\n")
        logger.write("*** Les 7 valeurs suivantes doivent rester nulles\n")
        analyse = [[], [], [], [], [], [], [], []]
        for a in acts:
            if not a.last_validation_state:
                analyse[0].append(a)
                need_mail = True
            if a.is_billed and (a.is_new() or a.is_absent()):
                analyse[1].append(a)
                need_mail = True
            if a.validation_locked and a.is_new():
                analyse[2].append(a)
                need_mail = True
            if a.is_billed and not a.validation_locked:
                analyse[3].append(a)
                need_mail = True
            if a.is_state('ACT_LOST'):
                analyse[4].append(a)
                need_mail = True
            if a.is_state('VALIDE') and not a.valide:
                analyse[5].append(a)
                need_mail = True
            if not a.parent_event:
                analyse[6].append(a)
                need_mail = True
            if a.invoice_set.all() and not a.already_billed:
                analyse[7].append(a)
                need_mail = True

        logger.write("$$$ Actes sans valeur 'last validation state' : %d\n" % len(analyse[0]))
        for a in analyse[0]:
            logger.write("\tActe %d : %s\n" % (a.id, a))
        logger.write("$$$ Actes facturés mais non pointés en présent : %d\n" % len(analyse[1]))
        for a in analyse[1]:
            logger.write("\tActe %d : %s\n" % (a.id, a))
        logger.write("$$$ Actes vérouillés mais non pointés : %d\n" % len(analyse[2]))
        for a in analyse[2]:
            logger.write("\tActe %d : %s\n" % (a.id, a))
        logger.write("$$$ Actes facturés mais non vérouillés : %d\n" % len(analyse[3]))
        for a in analyse[3]:
            logger.write("\tActe %d : %s\n" % (a.id, a))
        logger.write("$$$ Actes pointés perdus (déprécié) : %d\n" % len(analyse[4]))
        for a in analyse[4]:
            logger.write("\tActe %d : %s\n" % (a.id, a))
        logger.write("$$$ Actes validés mais avec valeur de contrôle non initialisée : %d\n" % len(analyse[5]))
        for a in analyse[5]:
            logger.write("\tActe %d : %s\n" % (a.id, a))
        logger.write("$$$ Actes sans événement parent : %d\n" % len(analyse[6]))
        for a in analyse[6]:
            logger.write("\tActe %d : %s\n" % (a.id, a))
        logger.write("$$$ Actes deja facturés mais already_billed est False : %d\n" % len(analyse[6]))
        for a in analyse[7]:
            logger.write("\tActe %d : %s\n" % (a.id, a))
        logger.write("\n")


        logger.write("Vérifications des factures\n")
        logger.write("--------------------------\n\n")

        for invoicing, invoice_list in invoices[service_name].items():
            logger.write("Facturation %d\n" % invoicing.seq_id)
            for invoice in invoice_list:
                if len(invoice.list_dates.split('$')) > invoice.acts.all().count():
                    need_mail = True
                    logger.write("$$$ Facture %d (%d, %d) patient %s avec des actes manquants\n" % (invoice.id, invoice.batch or 0, invoice.number or 0, PatientRecord.objects.get(id=invoice.patient_id)))
                    acts_dates = [datetime.strptime(d, '%d/%m/%Y').date() for d in invoice.list_dates.split('$')]
                    if service_name=='CMPP' and len(acts_dates) != len(set(acts_dates)):
                        print "$$$ Il y a plus d'un acte facturé le meme jour!"
                    logger.write("$$$ Nombre d'actes manquants %d\n" % (len(acts_dates)-invoice.acts.all().count()))
                    acts_missing_dates = set(acts_dates) - set([act.date for act in invoice.acts.all()])
                    for date in acts_missing_dates:
                        logger.write("$$$ Il manque un acte le %s\n" % date)
                else:
                    #Chech that dates of acts and dates in list_dates match
                    pass

                for act in invoice.acts.all():
                    if service_name=='CMPP':
                        if not act.is_billed and not act.is_lost:
                            logger.write("Facture %d (%d, %d) patient %s avec acte id %d %s à ce jour en refacturation (normal, autres factures %s)\n" % (invoice.id, invoice.batch or 0, invoice.number or 0, PatientRecord.objects.get(id=invoice.patient_id), act.id, act, str([str(i.number) for i in act.invoice_set.all()])))
                    else:
                        if not act.is_billed:
                            need_mail = True
                            logger.write("$$$ Facture %d (%d, %d) patient %s avec acte id %d %s non is_billed (anormal)\n" % (invoice.id, invoice.batch or 0, invoice.number or 0, PatientRecord.objects.get(id=invoice.patient_id), act.id, act))

        logger.write("\n")

        logger.write("Vérifications des actes facturés\n")
        logger.write("--------------------------------\n\n")


        acts_billed = Act.objects.filter(date__gte=ANALYSE_SDT.date(), patient__service__name=service_name, is_billed=True)
        for act in acts_billed:
            if not act.invoice_set.all():
                logger.write("$$$ Acte facturé sans facture id %d : %s\n" % (act.id, act))
                need_mail = True

        dic = {}
        if service_name=='CMPP':
            for act in acts_billed:
                dic.setdefault(act.patient, []).append(act)
            for patient, acts in dic.items():
                dates = []
                bad_dates = []
                for act in acts:
                    if act.date in dates and not act.date in bad_dates:
                        bad_dates.append(act.date)
                    else:
                        dates.append(act.date)
                for date in bad_dates:
                    need_mail = True
                    logger.write("$$$ %s a des actes facturés le même jour\n" % patient)
                    for act in Act.objects.filter(date=date, patient=patient, is_billed=True):
                        if act.invoice_set.all():
                            logger.write("Acte %d (factures %s) : %s\n" % (act.id, str([i.number for i in act.invoice_set.all()]), act))
                        else:
                            logger.write("Acte %d (sans factures) : %s\n" % (act.id, act))

        logger.write("\n")

        logger.write("Vérifications des jours de validation\n")
        logger.write("-------------------------------------\n\n")


        for date in [(ANALYSE_SDT + timedelta(days=i)).date() for i in range(0, (datetime.today().date()-ANALYSE_SDT.date()).days)]:
            # Actes non pointés
            acts = Act.objects.filter(last_validation_state__state_name='NON_VALIDE', date=date, patient__service__name=service_name)
            if acts:
                for act in acts:
                    if act.validation_locked:
                        need_mail = True
                        logger.write("$$$ Act %d : %s non validé mais verouillé\n" % (act.id, act))
                vms = ValidationMessage.objects.filter(validation_date=date, service__name=service_name)
                if not vms:
                    logger.write("Acte non pointés et aucune opération de validation pour le %s\n" % date)
                else:
                    last = ValidationMessage.objects.filter(validation_date=date, service__name=service_name).latest('when')
                    if last.what != 'Validation automatique':
                        logger.write("Jour %s dévérouillé le %s par %s\n" % (date, last.when, last.who))
                    else:
                        logger.write("$$$ Jour %s vérouillé le %s par %s\n" % (date, last.when, last.who))
                        need_mail = True
                        for act in acts:
                            logger.write("$$$ Act %d : %s\n" % (act.id, act))
                            logger.write("$$$ Evenement parent %d créé par %s le %s\n" % (act.parent_event.id, act.parent_event.creator, act.parent_event.create_date))
                            if act.parent_event.create_date < last.when:
                                logger.write("-------> Création de l'événement antérieur à la validation\n")
                logger.write("\n")

        logger.write("\n")


        logger.write("Vérifications des actes en double\n")
        logger.write("---------------------------------\n\n")

        for date in [(ANALYSE_SDT + timedelta(days=i)).date() for i in range(0, (datetime.today().date()-ANALYSE_SDT.date()).days)]:
            acts = Act.objects.filter(date=date, patient__service__name=service_name).order_by('time')
            if QUIET:
                # En double qu'on ne peut traiter.
                # On en exclue qu'un seul pour voir si un troisième apparait...
                acts = acts.exclude(id__in=(575896, 580500))
            acts_p = {}
            for a in acts:
                acts_p.setdefault(a.patient, []).append(a)
            for p, acts in acts_p.items():
                if len(acts) > 1:
                    acts_t = {}
                    for a in acts:
                        acts_t.setdefault((a.time, a.act_type), []).append(a)
                    for k, aa in acts_t.items():
                        if len(aa) > 1:
                            t, ty = k
                            logger.write("$$$ Actes en double pour %s le %s à %s\n" % (p, date, t))
                            acts_pe = {}
                            for a in aa:
                                acts_pe.setdefault(a.parent_event, []).append(a)
                            if len(aa) == len(acts_pe.keys()):
                                logger.write("$$$ Les événements parents sont distincts\n")
                            else:
                                logger.write("$$$ Il y a des événements parents communs\n")
                            for a in aa:
                                logger.write("\t %d : %s\n" % (a.id, a))
                                logger.write("\t\t %s\n" % a.last_validation_state)
                                if a.is_billed:
                                    logger.write("\t\t Acte facturé\n")
                                if a.invoice_set.all():
                                    logger.write("\t\tHistorique de facturation : %s\n" % str([i.number for i in a.invoice_set.all()]))
                                logger.write("\t\t evenement %d : %s, %s\n" % (a.parent_event.id, a.parent_event.creator, a.parent_event.create_date))
                                if a.parent_event.description:
                                    logger.write("\t\tCommentaire sur event %s\n" % a.parent_event.description.encode('utf-8'))
                                if a.parent_event.canceled:
                                    logger.write("\t\tC'est un événement annulé\n")
                                if a.parent_event.is_recurring():
                                    logger.write("\t\tC'est un événement récurrent\n")
                                if a.parent_event.exception_to:
                                    logger.write("\t\tC'est une exception à %d\n" % a.parent_event.exception_to.id)

        logger.write("\n\n")


    if need_mail or ALWAYS_SEND_MAIL:
        # send_mail
        pass

    logger.write("Fin du script de contôle de Calebasse : %s" % datetime.utcnow())
    old_fn = logger.name
    logger.close()
    os.rename(old_fn, logger_fn)
