# passerelle.contrib.agoraplus
# Copyright (C) 2015  Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import unicodedata
import re
from datetime import datetime, timedelta
from decimal import Decimal
import logging

# handle years before 1900
from django.utils import datetime_safe

# NNNN@mailprov.no emails are not real ones: we will ignore them.
# (They are used by Agora+ to create "fake" login for each user id=NNNN)
PROVISIONING_DOMAIN = 'mailprov.no'
DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%S'

# invoices possible status
PAID_INVOICE = 1
UNPAID_INVOICE = 2
LITIGATION_INVOICE = 3

logger = logging.getLogger('passerelle.contrib.agoraplus')

def slugify(s, space='-'):
    if s is None:
        return ''
    if not isinstance(s, unicode):
        s = s.decode('utf-8', errors='ignore')
    s = unicodedata.normalize('NFKD', s).encode('ascii', 'ignore')
    s = re.sub(r'[^\w\s\'%s]' % space, '', s).strip().lower()
    s = re.sub(r'[\s\'%s]+' % space, space, s)
    return s

def normalize_date(date):
    return u'%s' % datetime_safe.datetime.strptime(date, '%d/%m/%Y').strftime('%Y-%m-%d')

def denormalize_date(date):
    return u'%s' % datetime_safe.datetime.strptime(date, '%Y-%m-%d').strftime('%d/%m/%Y')

def normalize_reference(reference):
    new_reference = {}
    new_reference['id'] = u'%s' % reference['ID']
    new_reference['text'] = reference.get('NAME') or reference.get('NOM') or u''
    if 'CP' in reference:
        new_reference['post_code'] = reference['CP']
    if 'CODE_POSTAL' in reference:
        new_reference['post_code'] = reference['CODE_POSTAL']
    if 'NAME_VILLE' in reference and 'ID_VILLE' in reference:
        new_reference['city'] = {
                'id': u'%s' % reference['ID_VILLE'],
                'text': reference['NAME_VILLE'],
        }
    return new_reference

def normalize_address(address):
    new_address = {
            'number': u'%s' % address['numVoie'],
            'btq': {
                'text': address['btq']['libelle'],
                'id': u'%s' % address['btq']['id'],
            },
            'type_of_street': {
                'text': address['typeVoie']['nom'],
                'id': u'%s' % address['typeVoie']['id'],
            },
            'street': {
                'text': address['voie']['nom'],
                'id': u'%s' % address['voie']['id'],
            },
            'complements': address['complementAdresse'],
            'post_code': address['commune']['cp'],
            'city': {
                'text': address['commune']['nom'],
                'id': u'%s' % address['commune']['id'],
            },
    }
    if 'id' in address:
        new_address['id'] = u'%s' % address['id']
    new_address['text'] = u'{number}{btq[text]} {type_of_street[text]} {street[text]}'.format(**new_address).strip()
    new_address['full'] = new_address['text']
    end = u'{post_code} {city[text]}'.format(**new_address).strip()
    if end:
        new_address['full'] += u', ' + end
    return new_address

def normalize_person(person):
    new_person = {}
    if 'id' in person:
        new_person['id'] = u'%s' % person['id']
    new_person['first_name'] = person['prenom']
    new_person['last_name'] = person['nom']
    new_person['text'] = u'%(first_name)s %(last_name)s' % new_person
    if 'position' in person:
        new_person['index'] = int(person['position'])
    if person.get('dateNaissance'):
        new_person['birthdate'] = normalize_date(person['dateNaissance'])
    if 'villeNaissance' in person:
        new_person['birth_city'] = person['villeNaissance']
    if 'paysNaissance' in person:
        new_person['birth_country'] = person['paysNaissance']
    if 'sexe' in person:
        new_person['sex'] = person['sexe'][0] # u'M' or u'F'
    if 'civilite' in person:
        new_person['title'] = {
                'id': u'%s' % person['civilite']['id'],
                'text': person['civilite']['nom'],
                }
    if 'email' in person:
        new_person['login'] = person['email']
        if not person['email'].endswith('@' + PROVISIONING_DOMAIN):
            # real email
            new_person['email'] = person['email']

    # child
    if 'mobile' in person:
        new_person['cellphone'] = person['mobile']
    if 'etablissementScolaire' in person:
        new_person['school'] = {
                'id': u'%s' % person['etablissementScolaire']['id'],
                'text': person['etablissementScolaire']['designation'],
                }
        if 'niveauInscription' in person:
            new_person['school']['grade'] = {
                    'id': u'%s' % person['niveauInscription']['id'],
                    'text': person['niveauInscription']['designation'],
                    }
    if 'autoriteParentale' in person:
        new_person['parental_authority'] = [
                { 'id': u'%s' % adult['id'] }
                for adult in person['autoriteParentale']
                if adult['type'] == 'representant'
                ]

    # adult
    if 'adresse' in person:
        new_person['address'] = normalize_address(person['adresse'])
    if 'fixPerso' in person:
        new_person['phone'] = person['fixPerso']
    if 'mobilePerso' in person:
        new_person['cellphone'] = person['mobilePerso']
    if 'profession' in person:
        new_person['profession'] = person['profession']
    if 'employeur' in person:
        new_person['employer'] = person['employeur']
    if 'telEmployeur' in person:
        new_person['employer_phone'] = person['telEmployeur']
    if 'adresseEmployeur' in person:
        new_person['employer_address'] = normalize_address(person['adresseEmployeur'])

    # contact
    if 'enfants' in person:
        new_person['children'] = [
                {
                    'child_id': u'%s' % item['id'],
                    'link': {
                        'id': u'%s' % item['lien']['id'],
                        'text': u'%s' % item['lien']['nom'],
                        },
                    'parental_authority': bool(int(item['autoriteParentale'])),
                    'index': item['rang'],
                    'banned': bool(int(item['interdiction'])),
                }
                for item in person['enfants']]
    return new_person

def normalize_invoice(invoice):
    """
    Input invoice data to format
    {u'dateEmission': u'2015-06-23T00:00:00',
    u'dateLimitePayment': u'2015-07-17T00:00:00',
    u'datePrelevement': u'2015-06-30T00:00:00',
    u'id': u'9122',
    u'montantDu': u'0',
    u'nomFacturation': u'ACTIVITES PERISCOLAIRES MAI 2015',
    u'paye': u'54.58',
    u'prelevement': False,
    u'publication': False,
    u'statutEmission': {u'id': 1, u'name': u'pay\xe9e'},
    u'total': u'54.58'}
    """
    if not invoice.get('publication'):
        return None
    invoice['id'] = str(invoice['id'])
    invoice['display_id'] = invoice['id']
    invoice['total_amount'] = Decimal(invoice['total'])
    invoice['amount'] = Decimal(invoice['montantDu'])
    invoice['has_pdf'] = True
    invoice['created'] = datetime.strptime(invoice['dateEmission'], DATETIME_FORMAT)
    invoice['label'] = invoice['nomFacturation']
    invoice['pay_limit_date'] = datetime.strptime(invoice['dateLimitePayment'], DATETIME_FORMAT)
    status = invoice['statutEmission'].get('id')
    autobilling = invoice['prelevement']
    invoice['online_payment'] = False
    if autobilling:
        invoice['no_online_payment_reason'] = 'autobilling'
        invoice['online_payment'] = False

    if status == PAID_INVOICE:
        invoice['paid'] = True
    elif status == UNPAID_INVOICE:
        invoice['paid'] = False
        if not autobilling:
            invoice['online_payment'] = True
    elif status == LITIGATION_INVOICE:
        invoice['paid'] = False
        invoice['no_online_payment_reason'] = 'litigation'
    else:
        logger.warning('unknown invoice status: %s' % status)
        return None
    return invoice

def normalize_family(family):
    new_family = {}
    if 'id' in family:
        new_family['id'] = u'%s' % family['id']
    new_family['adults'] = [normalize_person(p) for p in family['Representants']]
    if len(new_family['adults']) > 0:
        new_family['address'] = new_family['adults'][0]['address']
    informations = {}
    for k,v in family.get('Informations complementaires', {}).items():
        if k == 'situationFamiliale':
            informations['situation'] = {
                    'id': u'%s' % v['id'],
                    'text': u'%s' % v['libelle'],
                    }
        elif k == 'allocataire':
            adult_id = u'%s' % v
            for adult in new_family['adults']:
                if adult['id'] == adult_id:
                    informations['allowance_adult'] = {
                            'id': adult.get('index'),
                            'text': adult['text'],
                            }
                    break
        elif k == 'numAlloc':
            informations['allowance_number'] = u'%s' % v
        elif k == 'nbEnfants':
            informations['number_of_children'] = u'%s' % v
        elif k == 'regime':
            informations['regime'] = {
                    'id': u'%s' % v['id'],
                    'text': v['name'],
                    }
        elif k == 'A.E.E.H':
            informations['allowance_aeeh'] = u'%s' % v
    new_family['informations'] = informations

    # build links between children and contacts
    children = {}
    for child in family['Enfants']:
        nchild = normalize_person(child)
        children[nchild['id']] = nchild
    contacts = []
    for contact in family['Contacts']:
        contact = normalize_person(contact)
        for child in contact['children']:
            child['text'] = children.get(child['child_id'], {}).get('text')
        contacts.append(contact)
    new_family['children'] = children.values()
    new_family['contacts'] = contacts

    return new_family

def normalize_school(school):
    new_school = {}
    new_school['id'] = u'%s' % school['ID']
    new_school['text'] = school.get('NAME') or u''
    address = ''
    if 'NUMERO_1' in school:
        address += u'%s ' % school['NUMERO_1']
    if 'TYPE_VOIE' in school:
        address += u'%s ' % school['TYPE_VOIE']
    if 'NOM_VOIE' in school:
        address += u'%s' % school['NOM_VOIE']
    new_school['address'] = address
    if 'VILLE' in school:
        new_school['city'] = school['VILLE']
    if 'CODE_POSTAL':
        new_school['post_code'] = school['CODE_POSTAL']
    return new_school

def normalize_planning(planning):
    new_planning = {}
    new_planning['date'] = planning['date'][:10]
    new_planning['year'] = planning['date'][0:4]
    new_planning['month'] = planning['date'][5:7]
    new_planning['expected_in'] = planning['arriveePrev']
    new_planning['in'] = planning['arriveeReelle']
    new_planning['expected_out'] = planning['departPrev']
    new_planning['out'] = planning['departReel']
    new_planning['message'] = planning['typeAbsence'].get('name', '').strip()
    new_planning['absent'] = (new_planning['in'] == '00:00' and
                              new_planning['out'] == '00:00') or (not new_planning['in'] and
                              not new_planning['out']) or planning['typeAbsence'].get('id')
    new_planning['deductible'] = planning['typeAbsence'].get('deductible') == 'TRUE'
    new_planning['absence_name'] = planning['typeAbsence'].get('name')
    new_planning['differ'] = (new_planning['in'] != new_planning['expected_in'] and
                              new_planning['out'] != new_planning['expected_out'])
    return new_planning

def normalize_nursery_enroll_results(results):
    """
    return only last month result, if exists
    """
    if not results:
        return {'decision': ''}
    result = results.pop()
    try:
        date = datetime.strptime(result['dateCommission'], '%d/%m/%Y').date()
    except ValueError:
        date = datetime.strptime(result['dateCommission'], '%d/%m/%y').date()
    if (datetime.today().date() - date).days > 30:
        return {'decision': ''}
    new_result = {}
    new_result['date'] = date
    new_result['date_fr'] = date.strftime('%d/%m/%Y')
    new_result['decision'] = slugify(result['decision'])
    new_result['proposed_structure'] = result['strctProposee']
    if result.get('dateDecisionFammille'):
        try:
            date = datetime.strptime(result['dateDecisionFammille'], '%d/%m/%Y').date()
        except ValueError:
            date = datetime.strptime(result['dateDecisionFammille'], '%d/%m/%y').date()
        new_result['family_decision_date'] = date
        new_result['family_decision_date_fr'] = date.strftime('%d/%m/%Y')
    else:
        new_result['family_decision_date'] = ''
        new_result['family_decision_date_fr'] = ''
    new_result['family_decision'] = result.get('decisionFamille') or ''
    new_result['family_decision_reason'] = result.get('MotifRefusFamille') or ''
    new_result['comment'] = result.get('commentaire') or ''
    if result.get('dateMaintien'):
        try:
            date = datetime.strptime(result['dateMaintien'], '%d/%m/%Y').date()
        except ValueError:
            date = datetime.strptime(result['dateMaintien'], '%d/%m/%y').date()
        new_result['maintain_date'] = date
        new_result['maintain_date_fr'] = date.strftime('%d/%m/%Y')
    else:
        new_result['maintain_date'] = ''
        new_result['maintain_date_fr'] = ''
    return new_result

def normalize_school_enrollment(enrollment):
    child = enrollment['enfant']
    year = enrollment['anneeRef']
    child_fullname = '%s %s' % (child['prenom'], child['nom'])
    school = enrollment['etablissementAffectation']
    enrollment_level = enrollment['niveau']
    return {'id': enrollment['idInscScol'], 'child_id': child['id'],
            'year_id': year['id'],
            'text': '%s, %s / %s, %s' % (child_fullname, school['name'],
                            enrollment_level['name'], year['name']),
            }
