# -*- coding: utf-8 -*-
"""
Version élève exercices du cours  
sur l'indexation et la recherche dans une table
"""
import re    #module pour traiter des expressions régulières
import csv   #module pour traiter les fichiers CSV


#%% Exercice 2

# variables globales

#nombre de jours par mois
NBJOURS_MOIS = {'normale' : [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30 ,31],
                'bissextile' : [0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30 ,31] }

#Numéros des départements
DEPARTEMENTS = [str(k).zfill(2) for k in range(1, 96)] + ['971', '972', '973', '974', '975', '2A', '2B']

# fonctions de lecture / écriture de fichiers CSV
def lecture_csv(fichier, delimiteur):
    """
    Paramètre : un chemin vers un fichier CSV
    Valeur renvoyée : un tableau de dictionnaires, extraction de la table contenue dans le fichier
    """
    f = open(fichier, mode = 'r', encoding = 'utf8', newline='')
    reader = csv.DictReader(f, delimiter = delimiteur)  #création de l'objet reader
    "à compléter"
    f.close()
    return table

def ecriture_csv(table, fichier, delimiteur):
    """
    Paramètre : 
        un chemin vers un fichier CSV
        une table comme tableau de dictionnaires partageant les mêmes clefs, de valeurs str
    Valeur renvoyée :
        None, écrit table dans fichier avec Dictriter du  module CSV 
    """
    g = open(fichier, mode = 'w', encoding = 'utf8', newline='')
    attributs = list(table[0].keys())
    writer = csv.DictWriter(g, delimiter = delimiteur, fieldnames = attributs) #création de l'objet writer
    "à compléter"
    g.close()

# Fonctions de validation des données


def valide_email(email):
    """
    Paramètre : email de type str
    Valeur renvoyée : booléen indiquant si email de format valide
    """
    # Expression régulière pour valider un email 
    regex = '^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w+$' 
    return re.search(regex,email) is not None

def valide_departement(departement):
    return departement in DEPARTEMENTS

def valide_visites(visites):
    return int(visites) >= 0

def valide_depenses(depenses):
    return float(depenses) >= 0

def bissextile(a):
    """
    Paramètre : a de type int représentant une année
    Valeur renvoyée  : booléen indiquant si l'année est bissextile
    """
    "à compléter"
    
def test_bissextile():
    """Tests unitaires pour la fonction bissextile"""
    assert bissextile(1900) == False, "1900 n'est pas bissextile"
    assert bissextile(2000) == True, "2000 est bissextile"
    assert bissextile(2020) == True, "2020 est bissextile"
    assert bissextile(2023) == False, "2023 n'est pas bissextile"
    print("test_bissextile() réussi")


def valide_annee(j):
    """
    Paramètre : j de type int représentant une année
    Valeur renvoyée  : booléen indiquant si  1920 <= j <= 2005
    """
    return isinstance(j, int) and  1920 <= j <= 2005


def valide_mois(m):
    """
    Paramètre : m de type int représentant un mois
    Valeur renvoyée  : booléen indiquant si le mois est valide (entre 1 et 12)
    """
    "à compléter"
    
def test_valide_mois():
    """Tests unitaires pour la fonction valide_mois"""
    assert valide_mois(2.0) == False, "2.0 n'est pas un mois valide"
    assert valide_mois("2") == False, " '2' n'est pas un mois valide"
    assert valide_mois(2) == True, "2 est un mois valide"
    assert valide_mois(-2) == False, "-2 n'est pas un mois valide"
    assert valide_mois(13) == False, "13 n'est pas un mois valide"
    assert valide_mois(0) == False, "0 n'est pas un mois valide"
    assert valide_mois(12) == True, "12 est un mois valide"
    print("test_valide_mois() réussi")

def valide_jour(a, m, j):
    """
    Paramètre : a, m, j de type int représentant l'année, le mois et le jour
    Valeur renvoyée  : booléen indiquant si le jour est valide pour l'année et le mois donnés
    """
    "à compléter"
    
def test_valide_jour():
    """Tests unitaires pour la fonction valide_jour"""
    assert valide_jour(1921,2,29) == False, "Le 29/02/1921 n'est pas valide"
    assert valide_jour(2000,2,29) == True, "Le 29/02/2000 est valide"
    assert valide_jour(2000,11,31) == False, "Le 31/11/2000 est invalide"
    # à vous de compléter avec d'autre tests
    print("test_valide_jour() réussi")

def valide_naissance(date):
    """
    Paramètre : date de type str au format 'année-mois-jour', ex: '2002-01-07'
    Valeur renvoyée  : booléen indiquant si le jour est valide pour l'année et le mois donnés
    """
    a, m, j = date.split('-')
    "à compléter"

def test_valide_naissance():
    """Tests unitaires pour la fonction valide_jour"""
    assert valide_naissance('1920-02-29') == True, "Le 29/02/1900 est  valide"
    assert valide_naissance('1920-02-30') == False, "Le 30/02/1900 n'est pas valide"
    assert valide_naissance('1900-01-01') == False, "Le 01/01/1900 n'est pas valide"
    assert valide_naissance('1920-06-31') == False, "Le 31/06/1920 n'est pas valide"
    # à vous de compléter avec d'autre tests
    print("test_valide_naissance() réussi")

def valide_enregistrement(enreg):
    """
    Paramètre : un enregistrement de type dictionnaire
    Valeur renvoyée  : booléen indiquant si toutes les valeurs des attibuts sont valides
    """
    "à compléter"


# Fonctions de conversion d'enregistrement

def conversion_vers_table(enregistrement):
    """
    Paramètre : un enregistrement de type dictionnaire
    Valeur renvoyée  : un enregistrement de type dictionnaire avec conversion des valeurs dans le type cible
    """
    return { 'nom' : enregistrement['nom'],
            'prénom'  : enregistrement['prénom'],
            'email' : enregistrement['email'],
            'département' : enregistrement['département'],
            'naissance' : enregistrement['naissance'],
            'visites' : "à compléter",
            'dépenses' : "à compléter"
            }

def conversion_vers_fichier(enregistrement):
    """
    Paramètre : un enregistrement de type dictionnaire
    Valeur renvoyée  : un enregistrement de type dictionnaire avec conversion des valeurs dans le type str
    """
    return { 'nom' : enregistrement['nom'],
            'prénom'  : enregistrement['prénom'],
            'email' : enregistrement['email'],
            'département' : enregistrement['département'],
            'naissance' : enregistrement['naissance'],
            'visites' : str(enregistrement['visites']),
            'dépenses' : str(enregistrement['dépenses'])
            }

def test_integration():
    """Test d'intégration de l'ensemble des fonctions"""
    #Traitement / validation / filtrage
    table = lecture_csv('clients_avec_erreurs.csv',',')
    table_valide = [conversion_vers_table(enregistrement) for enregistrement in table if valide_enregistrement(enregistrement)]
    # postconditions / tests
    assert len(table) == 1000 and len(table_valide) == 635
    print(table_valide[0])
    assert table_valide[0] == {'nom': 'Bailly', 'prénom': 'Aurélie', 'email': 'abailly1@gmail.com', 
                               'département': '22', 'naissance': '1986-09-22',
                               'visites': 54, 'dépenses': 2397.57}
    table_valide_str = [conversion_vers_fichier(enregistrement) for enregistrement in table_valide]
     #écriture de la table validée
    ecriture_csv(table_valide_str, 'clients_sans_erreurs.csv', ',')
    print("Test d'intégration réussi")
    
# Décommentez progressivement les tests 
#test_bissextile()
#test_valide_mois()
#test_valide_jour()
#test_valide_naissance()
#test_integration()

def main():
    """Code client"""
    #Traitement / validation / filtrage
    table = lecture_csv('clients_avec_erreurs.csv',',')
    table_valide = [conversion_vers_table(enregistrement) for enregistrement in table if valide_enregistrement(enregistrement)]
    # postconditions / tests
    assert len(table) == 1000 and len(table_valide) == 635
    assert table_valide[0] == {'nom': 'Bailly', 'prénom': 'Aurélie', 'email': 'abailly1@gmail.com', 
                               'département': '22', 'naissance': '1986-09-22',
                               'visites': 54, 'dépenses': 2397.57}
    table_valide_str = [conversion_vers_fichier(enregistrement) for enregistrement in table_valide]
     #écriture de la table validée
    ecriture_csv(table_valide_str, 'clients_sans_erreurs.csv', ',')

# code client
if __name__ == "__main__":
    "décommentez pour exécuter le code client"
    #main()
