from GlobalVariables import certificat_dict
import datetime
import hashlib
from RSA import decode_public
from Errors import *


def check_valeur_signature(signature, certificat=None):
    print("Vérification de signature")
    # 0) récupérer le certificat
    if not certificat:
        certificat_ID = signature.get_certificat_ID()
        if certificat_ID not in certificat_dict:
            raise CertificateError("Certificat non existant")
        certificat = certificat_dict[certificat_ID]
    cle_publique = certificat.get_cle_publique()
    
    # 1) calculer l'empreinte sur l'information
    result = hashlib.sha256(signature.get_information().encode())
    hash_value = result.digest()
    
    # 3) récupérer l'empreinte via la signature
    empreinte = decode_public(cle_publique, signature.get_valeur_signature())
    
    # 4) vérifier la correspondance
    valid = str(hash_value) == str(empreinte)
    
    if not valid:
        print("Erreur signature invalide")
    return valid


def check_valeur_horo(horodatage, certificat=None):
    sign_horo = horodatage.get_signature_horo()
    valid_sign_horo = check_valeur_signature(sign_horo, certificat=certificat)
    heure_date = horodatage.get_heure_date()
    info = horodatage.get_info()
    return valid_sign_horo, heure_date, info


def check_certificat(certificat, time_validation=None, time_horodatage=None, CRL=None):
    print("Vérification du certificat" + str(certificat.get_ID()) + " de " + certificat.get_identite())
    prestataire = certificat.get_prestataire()

    if not time_validation:
        time_validation = datetime.datetime.now()
    
    if certificat.get_date_fin_validite() < time_validation:
        print("Erreur : certificat " + str(certificat.get_ID()) + " expiré au moment indiqué par la validation")
        return False
    
    if not CRL:
        CRL = prestataire.get_liste_revocation()
    if certificat.get_ID() in CRL:
        timing_revoked = CRL[certificat.get_ID()]
        if not time_horodatage:
            time_horodatage = datetime.datetime.now()
        if timing_revoked < time_horodatage:
            print("Erreur : certificat revoqué", timing_revoked)
            return False
    
    valid = check_valeur_signature(certificat.get_signature_certif())
    
    return valid


def check_signature(signature):
    type_signature = signature.get_type()
    if type_signature == "signature basique":
        certificat_ID = signature.get_certificat_ID()
        if certificat_ID not in certificat_dict:
            raise CertificateError("Certificat non existant")
        certificat = certificat_dict[certificat_ID]
        valid = check_certificat(certificat)
        valid = valid and check_valeur_signature(signature, certificat)
        return valid, "signature basique"
    elif type_signature == "signature horodatee":
        horodatage = signature.get_horodatage()
        valid_horo, date_heure_horo, _ = check_valeur_horo(horodatage)
        certificat_horo = horodatage.get_certificat_horo()
        valid_horo = valid_horo and check_certificat(certificat_horo)
        if not valid_horo:
            return False, "signature horodatee"
        signatureBasique = signature.get_signatureBasique()
        certificat_ID = signatureBasique.get_certificat_ID()
        if certificat_ID not in certificat_dict:
            raise CertificateError("Certificat non existant")
        certificat = certificat_dict[certificat_ID]
        valid = check_certificat(certificat, time_horodatage=date_heure_horo)
        valid = valid and check_valeur_signature(signatureBasique, certificat)
        return valid, "signature horodatee"
    elif type_signature == "signature LT":
        signatureHorodatee = signature.get_signatureHorodatee()
        horodatage = signatureHorodatee.get_horodatage()
        certificat_horo = signature.get_certif_horodatage()
        CRL_sign = signature.get_CRL_sign()
        CRL_horo = signature.get_CRL_horo()
        certificat_horo_ID = certificat_horo.get_ID()
        if certificat_horo_ID in certificat_dict:
            CRL_horo_fresh = certificat_dict[certificat_horo_ID].get_prestataire().get_liste_revocation()
            if not certificat_horo_ID in CRL_horo and certificat_horo_ID in CRL_horo_fresh:
                raise FreshnessError("Informations CRL par rapport au certificat concerné"
                                     " présentes dans la signature ne sont pas à jour")
        valid_horo, date_heure_horo, _ = check_valeur_horo(horodatage, certificat=certificat_horo)
        valid_horo = valid_horo and check_certificat(certificat_horo, CRL=CRL_horo)
        if not valid_horo:
            return False, "signature LT"
        signatureBasique = signatureHorodatee.get_signatureBasique()
        certificat = signature.get_certif_signature()
        valid = check_certificat(certificat, time_horodatage=date_heure_horo, CRL=CRL_sign)
        valid = valid and check_valeur_signature(signatureBasique, certificat)
        return valid, "signature LT"
    elif type_signature == "signature LTA":
        horodatage = signature.get_horodatage()
        certificat_horo = horodatage.get_certificat_horo()  # en ligne
        valid_horo, date_heure_horo, _ = check_valeur_horo(horodatage, certificat=certificat_horo)
        valid_horo = valid_horo and check_certificat(certificat_horo)
        if not valid_horo:
            return False, "signature LTA"
        actual_signature = signature
        previous_signatureLT_A = signature.get_signatureLT_A()
        time_valid = date_heure_horo
        while (previous_signatureLT_A.get_type() == "signature LTA"):  # TODO verif dates
            horodatage = previous_signatureLT_A.get_horodatage()
            certificat_horo = actual_signature.get_certif_previous_horo()
            valid_horo, date_heure_horo, _ = check_valeur_horo(horodatage, certificat=certificat_horo)
            CRL_horo = actual_signature.get_CRL_horo()
            valid_horo = valid_horo and check_certificat(certificat_horo, CRL=CRL_horo, time_validation=time_valid,
                                                         time_horodatage=time_valid)
            if not valid_horo:
                return False, "signature LTA"
            actual_signature = previous_signatureLT_A
            previous_signatureLT_A = previous_signatureLT_A.get_signatureLT_A()
            time_valid = date_heure_horo
        signatureHorodatee = previous_signatureLT_A.get_signatureHorodatee()
        horodatage = signatureHorodatee.get_horodatage()
        certificat_horo = previous_signatureLT_A.get_certif_horodatage()
        CRL_sign = previous_signatureLT_A.get_CRL_sign()
        CRL_horo = previous_signatureLT_A.get_CRL_horo()
        valid_horo, date_heure_horo, _ = check_valeur_horo(horodatage, certificat=certificat_horo)
        valid_horo = valid_horo and check_certificat(certificat_horo, CRL=CRL_horo, time_validation=time_valid,
                                                     time_horodatage=time_valid)
        if not valid_horo:
            return False, "signature LTA"
        signatureBasique = signatureHorodatee.get_signatureBasique()
        certificat = previous_signatureLT_A.get_certif_signature()
        valid = check_certificat(certificat, time_validation=date_heure_horo, time_horodatage=date_heure_horo,
                                 CRL=CRL_sign)
        valid = valid and check_valeur_signature(signatureBasique, certificat)
        return valid, "signature LTA"
    
    else:
        return False, "pas de type de signature"