import { ValidationError, isArray, validate } from "class-validator";
import { myDataSource } from "../../../configs/data-source";
import { Paiement } from "../entity/Paiement";
import { Request, Response } from "express";
import { generateServerErrorCode, success, validateMessage } from "../../../configs/response";
import { Redevance } from "../../gestiondesabonnements/entity/Redevance";
import { ModePaiement } from "../entity/ModePaiement";
import { Abonnement } from "../../gestiondesabonnements/entity/Abonnement";
import { Campagne } from "../../gestiondescampagnes/entity/Campagne"
import { replaceAndSend } from "../../gestiondesnotifications/controller/envoieSMS";
import { recuPaiementServiceHtml, recuReabonnement } from "../../gestiondesattestations/controller/document.controller";
import { paginationAndRechercheInit } from "../../../configs/paginationAndRechercheInit";
import { Brackets } from 'typeorm';
import { checkRelationsOneToMany } from "../../../configs/checkRelationsOneToManyBeforDelete";
import { checkRole, isEmptyObject } from "../../function.ts/function";
import * as path from 'path';
import * as fs from 'fs';
import { sendEmail } from "../../gestiondesnotifications/controller/envoieMail";
const crypto = require('crypto');



export const createPaiement = async (req: Request, res: Response) => {
    req.body["datePaiement"] = new Date();
    req.body["refPaiement"] = "PA";
    const paiement = myDataSource.getRepository(Paiement).create(req.body);
    //paiement.datePaiement = new Date()
    const errors = await validate(paiement)
    if (errors.length > 0) {
        const message = validateMessage(errors);
        return generateServerErrorCode(res, 400, errors, message)
    }
    await myDataSource.getRepository(Paiement).save(paiement)
        .then((paiement: Paiement | Paiement[]) => {
            var refPaiement = '';
            if (!Array.isArray(paiement)) {
                refPaiement = paiement.refPaiement;
                console.log("ILLLL EEEEE")
                recuPaiementServiceHtml(paiement.id, req, res);
            }
            const message = `Le paiement ${refPaiement} a bien été crée.`
            return success(res, 201, paiement, message);
        })
        .catch(error => {
            if (error instanceof ValidationError) {
                return generateServerErrorCode(res, 400, error, 'Ce paiement existe déjà')
            }
            if (error.code == "ER_DUP_ENTRY") {
                return generateServerErrorCode(res, 400, error, 'Ce paiement existe déjà')
            }
            const message = `Le paiement n'a pas pu être ajouté. Réessayez dans quelques instants.`
            return generateServerErrorCode(res, 500, error, message)
        })
}

export const createPaiementRedevance = async (req: Request, res: Response) => {
    const paiement = new Paiement();
    paiement.abonnement = await myDataSource.getRepository(Abonnement).findOneBy({ id: parseInt(req.body.abonnement) });
    paiement.datePaiement = new Date();
    paiement.modePaiement = await myDataSource.getRepository(ModePaiement).findOneBy({ id: parseInt(req.body.modePaiement) });
    paiement.montantPaye = req.body.montantPaye;
    paiement.montantRestant = 0;
    paiement.agence = req.body.agenceId;
    paiement.userCreation = req.body.userCreation;
    paiement.montantRecu = req.body.montantRecu;
    paiement.transactionId = req.body.transactionId;
    const errors = await validate(paiement);
    const redevances = await myDataSource.getRepository(Redevance).findOneBy({ id: parseInt(req.body.redevance) });
    myDataSource.getRepository(Redevance).merge(
        redevances,
        {
            statut: "Payée"
        }
    );
    await myDataSource.getRepository(Paiement).save(paiement)
        .then(paiement => {
            const message = `Le paiement ${paiement.refPaiement} a bien été crée.`
            //envoie d'sms
            const result = replaceAndSend(3, paiement, paiement.abonnement.abonne.telephone);
            myDataSource.getRepository(Redevance).save(redevances).then((redevance) => {
                return success(res, 201, paiement, message);
            }).catch((error) => {
                if (error instanceof ValidationError) {
                    return generateServerErrorCode(res, 400, error, 'Ce paiement existe déjà')
                }
                if (error.code == "ER_DUP_ENTRY") {
                    return generateServerErrorCode(res, 400, error, 'Ce paiement existe déjà')
                }
                const message = `Le paiement n'a pas pu être ajouté. Réessayez dans quelques instants.`
                return generateServerErrorCode(res, 500, error, message)
            })

        })
        .catch(error => {
            if (error instanceof ValidationError) {
                return generateServerErrorCode(res, 400, error, 'Ce paiement existe déjà')
            }
            if (error.code == "ER_DUP_ENTRY") {
                return generateServerErrorCode(res, 400, error, 'Ce paiement existe déjà')
            }
            const message = `Le paiement n'a pas pu être ajouté. Réessayez dans quelques instants.`
            return generateServerErrorCode(res, 500, error, message)
        })

}

export const verifyExistingFile = async (req: Request, res: Response) => {
    let directory = req.body.dossier || "";
    let fileName = req.body.nomFichier || "";
    const uploadsDir = path.join(__dirname, '../../../../uploads');
    // let fileUrl = req.body.fileUrl || ""; 
    console.log("donner", req.body);
    if (!directory || !fileName) {
        const message = `Le dossier ou le nom du fichier est manquant.`
        return generateServerErrorCode(res, 400, "Bad Request", message);
    }
    const fileUrl = path.join(uploadsDir, directory, fileName);
    console.log("fileUrl", fileUrl);
    if (fs.existsSync(fileUrl)) {
        console.log("Le fichier existe déjà.");
        const message = `Le fichier existe.`
        return success(res, 200, { reference: fileUrl }, message);
    } else {
        console.log("Le fichier n'existe pas.");
        const message = `Le fichier n'existe pas.`
        return success(res, 204, { reference: fileUrl }, message);
        // return generateServerErrorCode(res, 404, "File Not Found", message);
    }
}

export const regenerFichierRecu = async (req: Request, res: Response) => {
    const recu = req.body.recu;
    try {
        if (!recu || !recu.paiement?.refPaiement) {
            const message = `La référence de paiement est manquante.`;
            return generateServerErrorCode(res, 400, "Bad Request", message);
        }
        // const filePath = path.join(uploadsDir, 'Facture', `${facture.reference}.pdf`);
        // if (fs.existsSync(filePath)) {
        //     fs.unlinkSync(filePath);
        // }
        // const pdf = recuReabonnement(resPaiement.id, req, res);
        const pdf = recuReabonnement(recu.paiement?.id, req, res);
        // if(facture.estNormalisee && facture.estNormalisee == true){
        //     await factureNormalisee(facture.id, req, res);
        // } else {
        //     await factureAvantaiement(facture.id, req, res);
        // }
        const message = `Le fichier de la facture a été régénéré avec succès.`
        return success(res, 200, { reference: recu.paiement?.refPaiement }, message);
    } catch (error) {
        const message = `Erreur lors de la régénération du fichier de la facture.`
        return generateServerErrorCode(res, 500, error, message);
    }
}

export const getPaiementByAbonne = async (req: Request, res: Response) => {
    await myDataSource.getRepository(Paiement).find({
        where: {
            abonnement: {
                abonne: {
                    id: parseInt(req.body.abonne)
                }
            }
        },
        relations: {
            abonnement: {
                abonne: true
            },
            redevances: true,
            service: true,
            modePaiement: true
        },
        order: {
            id: "DESC",
        },
    })
        .then(paiement => {
            if (paiement === null) {
                const message = `Le paiement demandé n'existe pas. Réessayez avec un autre identifiant.`
                return generateServerErrorCode(res, 400, "L'id n'existe pas", message)
            }
            const message = `Le paiement a bien été trouvé.`
            return success(res, 200, paiement, message);
        })
        .catch(error => {
            const message = `Le paiement n'a pas pu être récupéré. Réessayez dans quelques instants.`
            return generateServerErrorCode(res, 500, error, message)
        })
}

export const getPaiement = async (req: Request, res: Response) => {
    await myDataSource.getRepository(Paiement).findOne({
        where: { id: parseInt(req.params.id) },
        relations: {
            abonnement: true,
            redevances: true,
            service: true,
            modePaiement: true
        },
        order: {
            id: "DESC",
        },
    })
        .then(paiement => {
            if (paiement === null) {
                const message = `Le paiement demandé n'existe pas. Réessayez avec un autre identifiant.`
                return generateServerErrorCode(res, 400, "L'id n'existe pas", message)
            }
            const message = `Le paiement a bien été trouvé.`
            return success(res, 200, paiement, message);
        })
        .catch(error => {
            const message = `Le paiement n'a pas pu être récupéré. Réessayez dans quelques instants.`
            return generateServerErrorCode(res, 500, error, message)
        })
}

export const getAllPaiements = async (req: Request, res: Response) => {
    await myDataSource.getRepository(Paiement)
        .find({
            select: { modePaiement: { id: true, libelle: true } },
            relations: {
                abonnement: true,
                //redevance:true,
                service: true,
                modePaiement: true
            },
            order: {
                refPaiement: "DESC"
            }
        })
        .then(paiements => {
            const message = 'La liste des paiements a bien été récupéré.';
            return success(res, 200, paiements, message);
        }).catch(error => {
            const message = `La liste des paiements n'a pas pu être récupéré. Réessayez dans quelques instants.`
            return generateServerErrorCode(res, 500, error, message)
        })
}

export const getPaiements = async (req: Request, res: Response) => {
    await myDataSource.getRepository(Paiement).find({
        select: { modePaiement: { id: true, libelle: true } },
        relations: {
            abonnement: true,
            redevances: true,
            service: true,
            modePaiement: true
        },
        order: {
            refPaiement: "DESC"
        }
    })
        .then(paiements => {
            const message = 'La liste des paiements a bien été récupéré.'
            return success(res, 200, paiements, message);
        }).catch(error => {
            const message = `La liste des paiements n'a pas pu être récupéré. Réessayez dans quelques instants.`
            return generateServerErrorCode(res, 500, error, message)
        })
}

export const getpaiementsBykey = async (req: Request, res: Response) => {
    await (myDataSource.getRepository(Paiement)
        .createQueryBuilder("p")
        .select("p")
        .where("(p.refPaiement like :key1 OR p.montantPaye like :key1)", { key1: `%${req.params.cle}%` })
        .andWhere("p.deletedAt IS NULL")
        .getMany()
    )
        .then(paiements => {
            if (paiements === null) {
                const message = `Aucun élément ne correspond à votre recherche.`
                return generateServerErrorCode(res, 400, "Aucun élément ne correspond à votre recherche", message)
            }
            const message = `La récupération a bien été exécuté.`
            return success(res, 200, paiements, message);
        })
        .catch(error => {
            const message = `Aucune paiement n'a pas pu être récupéré faute d'une erreur . Réessayez dans quelques instants.`
            return generateServerErrorCode(res, 500, error, message)
        })
};

export const getpaiementsToService = async (req: Request, res: Response) => {
    const { page, limit, searchTerm, startIndex, searchQueries } = paginationAndRechercheInit(req, Paiement);
    let reque = await myDataSource.getRepository(Paiement)
        .createQueryBuilder("paiement")
        .leftJoinAndSelect("paiement.abonnement", "abonnement")
        .leftJoinAndSelect("paiement.demande", "demande")
        .leftJoinAndSelect("abonnement.abonne", "abonne")
        .leftJoinAndSelect("abonnement.boite", "boite")
        .leftJoinAndSelect("boite.bureau", "bure")
        .leftJoinAndSelect("abonnement.agence", "agence")
        .leftJoinAndSelect("abonnement.bureau", "bur")
        .leftJoinAndSelect("paiement.service", "service")
        .leftJoinAndSelect("paiement.agence", 'bureau')
        .leftJoinAndSelect("paiement.modePaiement", 'modePaiement')
        .leftJoinAndSelect("paiement.campagne", 'campagne')
        .leftJoinAndSelect("paiement.mpostbox", "mpostbox")
        .where("paiement.service IS NOT NULL")
        .andWhere("paiement.deletedAt IS NULL");
    if (req.body.abonne && typeof req.body.abonne === 'string') {
        reque = reque.andWhere("abonne.id = :val1", { val1: parseInt(req.body.abonne) })
    }
    if (searchQueries.length > 0) {
        reque.andWhere(new Brackets(qb => {
            qb.where(searchQueries.join(' OR '), { keyword: `%${searchTerm}%` })
        }));
    }
    const donnee = await checkRole(req);
    if (donnee == false) {
        if (req.body.agenceId) {
            reque.andWhere("(bureau.id =:bureau OR agence.id = :bureau OR bur.id = :bureau OR bure.id = :bureau)", { bureau: parseInt(req.body.agenceId) })
        }
    }
    await reque.orderBy("paiement.refPaiement", "DESC")
        .skip(startIndex)
        .take(limit)
        .getManyAndCount()
        .then(([data, totalElements]) => {
            if (data === null) {
                const message = `Aucun élément ne correspond à votre recherche.`;
                return generateServerErrorCode(res, 400, "Aucun élément ne correspond à votre recherche", message)
            }
            const message = `La récupération a bien été exécuté.`;
            const totalPages = Math.ceil(totalElements / limit);
            return success(res, 200, { data, totalPages, totalElements, limit }, message);
        })
        .catch(error => {
            const message = `Aucune paiement n'a pas pu être récupéré faute d'une erreur . Réessayez dans quelques instants.`
            return generateServerErrorCode(res, 500, error, message);
        })
};

export const getpaiementsNonService = async (req: Request, res: Response) => {
    const { page, limit, searchTerm, startIndex, searchQueries } = paginationAndRechercheInit(req, Paiement);
    let reque = await myDataSource.getRepository(Paiement)
        .createQueryBuilder("paiement")
        .leftJoin("paiement.service", "service")
        .innerJoinAndSelect("paiement.abonnement", "abonnement")
        .innerJoinAndSelect("abonnement.abonne", "abonne")
        .leftJoinAndSelect("paiement.redevance", 'redevance')
        .leftJoinAndSelect("paiement.agence", 'Bureau')
        .leftJoinAndSelect("paiement.modePaiement", 'ModePaiement')
        .leftJoinAndSelect("paiement.mpostbox", 'Mpostbox')
        //.where("service IS NOT NULL")
        .andWhere("paiement.deletedAt IS NULL");
    if (req.query.abonneid && typeof req.query.abonneid === 'string') {
        reque = reque.andWhere("abonne.id = :val1", { val1: parseInt(req.query.abonneid) });
    }
    if (searchQueries.length > 0) {
        reque.andWhere(new Brackets(qb => {
            qb.where(searchQueries.join(' OR '), { keyword: `%${searchTerm}%` })
        }));
    }
    reque.orderBy("paiement.refPaiement", "DESC")
        .skip(startIndex)
        .take(limit)
        .getManyAndCount()

        .then(([data, totalElements]) => {
            if (data === null) {
                const message = `Aucun élément ne correspond à votre recherche.`
                return generateServerErrorCode(res, 400, "Aucun élément ne correspond à votre recherche", message)
            }
            const message = `La récupération a bien été exécuté.`;
            const totalPages = Math.ceil(totalElements / limit);
            return success(res, 200, { data, totalPages, totalElements, limit }, message);
        })
        .catch(error => {
            const message = `Aucune paiement n'a pas pu être récupéré faute d'une erreur . Réessayez dans quelques instants.`
            return generateServerErrorCode(res, 500, error, message)
        })
};

export const getRedevancePayes = async (req: Request, res: Response) => {
    const { page, limit, searchTerm, startIndex, searchQueries } = paginationAndRechercheInit(req, Redevance);
    let reque = await myDataSource.getRepository(Redevance)
        .createQueryBuilder("redevance")
        .leftJoinAndSelect("redevance.paiement", "paiement")
        .leftJoinAndSelect("paiement.service", "service")
        .innerJoinAndSelect("redevance.abonnement", "abonnement")
        .innerJoinAndSelect("abonnement.abonne", "abonne")
        .leftJoinAndSelect("abonnement.boite", "boite")
        .leftJoinAndSelect("boite.bureau", "agence")
        .leftJoinAndSelect("abonnement.bureau", "bure")
        .leftJoinAndSelect("abonnement.agence", "bur")
        .leftJoinAndSelect("boite.adressePostale", "adressePostale")
        .leftJoinAndSelect("paiement.agence", 'bureau')
        .leftJoinAndSelect("paiement.modePaiement", 'modePaiement')
        .leftJoinAndSelect("paiement.mpostbox", 'mpostbox')
        .where("redevance.deletedAt IS NULL")
        .andWhere("redevance.paiement IS NOT NULL");
    if (req.body.abonne && typeof req.body.abonne === 'string') {
        reque = reque.andWhere("abonne.id = :val1", { val1: parseInt(req.body.abonne) });
    }
    if (searchQueries.length > 0) {
        reque.andWhere(new Brackets(qb => {
            qb.where(searchQueries.join(' OR '), { keyword: `%${searchTerm}%` })
        }));
    }
    const donnee: boolean = await checkRole(req);
    if (donnee == false) {
        if (req.body.agenceId) {
            reque.andWhere("(bureau.id =:bureau OR agence.id = :bureau OR bure.id = :bureau OR bur.id = :bureau)", { bureau: parseInt(req.body.agenceId) });
        }
    }
    reque.orderBy("redevance.refRedevance", "DESC")
        .skip(startIndex)
        .take(limit)
        .getManyAndCount()

        .then(([data, totalElements]) => {
            if (data === null) {
                const message = `Aucun élément ne correspond à votre recherche.`
                return generateServerErrorCode(res, 400, "Aucun élément ne correspond à votre recherche", message)
            }
            const message = `La récupération a bien été exécuté.`;
            const totalPages = Math.ceil(totalElements / limit);
            return success(res, 200, { data, totalPages, totalElements, limit }, message);
        })
        .catch(error => {
            const message = `Aucune paiement n'a pas pu être récupéré faute d'une erreur . Réessayez dans quelques instants.`
            return generateServerErrorCode(res, 500, error, message)
        })
};

export const createManyRedevanceAndPaiement = async (req: Request, res: Response) => {
    
    if (isEmptyObject(req.body)) {
        const message = `Le paiement n'a pas pu être ajouté. Les champs sont vides`
        return generateServerErrorCode(res, 500, "Champs vide", message)
    }
    var abonnement = null;
    if (req.body && req.body.abonnement) {
        //Commençons par récuperer l'abonnement 
        abonnement = await myDataSource.getRepository(Abonnement).findOneBy({ id: parseInt(req.body.abonnement), })
    } else {
        const message = `Abonnement non fourni`
        return generateServerErrorCode(res, 500, "Abonnement non fourni", message);
    }
    //Ensuite créons un tableau de l'objet Redevance
    const tableauDeRedevances: Redevance[] = [];
    const annees = req.body.annees;
    //Remplissage du tableau avec les redevances qui seront créées 
    for (let i = 0; i < (annees).length; i++) {
        //Création d'une redevance
        const redevance = new Redevance();
        redevance.abonnement = abonnement;
        redevance.montant = abonnement.loyer;
        redevance.annee = req.body.annees[i];
        redevance.dateRedevance = new Date();
        redevance.userCreation = req.body.userCreation;
        //Injection dans le tableau
        tableauDeRedevances.push(redevance);
    }
    await myDataSource.getRepository(Redevance).save(tableauDeRedevances)
        .then((tableauDeRedevances) => {
            //Creation du tableau de paiement
            const tableauDePaiements: Paiement[] = [];
            for (let j = 0; j < (tableauDeRedevances).length; j++) {
                //Création d'une redevance
                const paiement = new Paiement()
                // paiement.redevance = tableauDeRedevances[j];
                paiement.abonnement = tableauDeRedevances[j].abonnement;
                paiement.datePaiement = new Date();
                paiement.montantPaye = tableauDeRedevances[j].abonnement.montant;
                paiement.montantRecu = tableauDeRedevances[j].abonnement.montant;
                paiement.montantRestant = 0;
                paiement.agence = req.body.agenceId;
                paiement.userCreation = req.body.userCreation;
                //paiement.modePaiement = 2;
                //Injection dans le tableau
                tableauDePaiements.push(paiement);
            }
            myDataSource.getRepository(Paiement).save(tableauDePaiements)
                .then((tableauDePaiements) => {
                    return success(res, 200, tableauDePaiements, "Le paiement ont bien réussi");
                }).catch(error => {
                    if (error instanceof ValidationError) {
                        return generateServerErrorCode(res, 400, error, 'Ce paiement existe déjà')
                    }
                    if (error.code == "ER_DUP_ENTRY") {
                        return generateServerErrorCode(res, 400, error, 'Ce paiement existe déjà')
                    }
                    const message = `Le paiement n'a pas pu être ajouté. Réessayez dans quelques instants.`
                    return generateServerErrorCode(res, 500, error, message)
                })
        })
        .catch(error => {
            if (error instanceof ValidationError) {
                return generateServerErrorCode(res, 400, error, 'Cette redevance existe déjà')
            }
            if (error.code == "ER_DUP_ENTRY") {
                return generateServerErrorCode(res, 400, error, 'Cette redevance existe déjà')
            }
            const message = `Le paiement n'a pas pu être ajouté. Réessayez dans quelques instants.`
            return generateServerErrorCode(res, 500, error, message)
        })
};

function signUrl(url) {
    const hmac = crypto.createHmac('sha256', "Secret");
    return `${url}?signature=${hmac.update(url).digest('hex')}`;
}

export const createPaiementRedevanceByIdDuree = async (req: Request, res: Response) => {
    let resPaiement: Paiement;
    let redevances;
    let refs;
    console.log("REQQQQ ", req.body)
    console.log("ZZZZZZZ ", req.params)
    console.log(" CECI EST LE CONTENU DE NOTRE BODY == >", req.body)
    await myDataSource.manager.transaction(async (transactionalEntityManager) => {
        const abonnement = await myDataSource.getRepository(Abonnement).findOne({
            where: { id: parseInt(req.body.abonnement), },
            relations: {
                abonne: { categorieAbonne: true },
                boite: { adressePostale: true },
            }
        })
        const tableauDeRedevances: Redevance[] = [];
        const redevances = await myDataSource.getRepository(Redevance)
            .createQueryBuilder("r")
            .innerJoinAndSelect("r.abonnement", "a")
            .innerJoinAndSelect("a.abonne", "ab")
            .where("r.statut != :val", { val: "Payée" })
            .andWhere("a.id = :val1", { val1: req.body.abonnement })
            .orderBy("r.annee", "ASC")
            .getMany();
        const reste = (req.body.duree) - (redevances ? redevances.length : 0);
        var montantRed = 0;
        var montantPenalite = 0;

        //recherche de penalite
        if (redevances) {
            for (let i = 0; i < redevances.length; i++) {
                if ((redevances[i])) {
                    //ici je verifie s'il faut appliqué de penalite
                    if (new Date(`${redevances[i].annee}-01-01`) < new Date(`${new Date().getFullYear()}-03-01`) ){
                    // if (Number(redevances[i].annee) < Number(new Date().getFullYear())) {
                        montantPenalite = 3000;
                    }
                }
            }
        }

        var laDate = new Date();
        //Recheche d'une campagne
        const categorieAbonneId = abonnement.abonne.categorieAbonne?.id;
        let campagne = null;

        console.log("categorieAbonneId", categorieAbonneId);
        if (categorieAbonneId > 0) {
            campagne = await myDataSource.getRepository(Campagne)
                .createQueryBuilder("c")
                .where("c.typeDeCampagne = :rem", { rem: "Reduction" })
                .andWhere(":ladate BETWEEN c.dateDebut AND c.dateFin", { ladate: laDate })
                .andWhere("c.categorieAbonne = :categorieAbonneId", { categorieAbonneId: categorieAbonneId })
                .orderBy("c.id", "DESC")
                .limit(1)
                .getOne();
            // console.log("campagne trouvé", campagne);
        }
        if (campagne == null) {
            campagne = await myDataSource.getRepository(Campagne)
                .createQueryBuilder("c")
                .where("c.typeDeCampagne = :rem", { rem: "Reduction" })
                .andWhere(":ladate BETWEEN c.dateDebut AND c.dateFin", { ladate: laDate })
                .andWhere("c.categorieAbonne is null")
                .orderBy("c.id", "DESC")
                .limit(1)
                .getOne();
            // console.log("campagne trouvé2", campagne);
        }

        if (reste == 0) {
            for (let i = 0; i < (redevances).length; i++) {
                montantRed += redevances[i].montant;
                // redevances[i].montant = redevances[i].abonnement.loyer;
                redevances[i].statut = "Payée";
                tableauDeRedevances.push(redevances[i]);
            }
        }

        if (reste > 0) {
            var annne: number = 0;
            if (redevances) {
                for (let i = 0; i < (redevances).length; i++) {
                    montantRed += redevances[i].montant;
                    // redevances[i].montant = abonnement.loyer;
                    redevances[i].statut = "Payée";
                    annne = redevances[i].annee;
                    tableauDeRedevances.push(redevances[i]);
                }
            }
            if (annne == 0) {
                const dernierRedevance = await myDataSource.getRepository(Redevance)
                    .createQueryBuilder("r")
                    .innerJoin("r.abonnement", "a")
                    .where("a.id = :val1", { val1: req.body.abonnement })
                    .orderBy("r.annee", "DESC")
                    .getOne();
                if (dernierRedevance) {
                    annne = dernierRedevance.annee;
                } else {
                    const dateAbo: Date = new Date(abonnement.createdAt.toString());
                    annne = dateAbo.getFullYear();
                }
            }
            for (let i = 0; i < reste; i++) {
                annne++;
                montantRed += abonnement.loyer;
                const redevance = new Redevance();
                redevance.montant = abonnement.loyer;
                redevance.refRedevance = 'RE' + (Math.floor(Date.now() / 1000) + i);
                redevance.statut = "Payée";
                redevance.abonnement = abonnement;
                redevance.dateRedevance = new Date();
                redevance.annee = annne;
                redevance.arrieres = 0;
                redevance.userCreation = req.body.userCreation;
                tableauDeRedevances.push(redevance);
            }
        }
        if (reste < 0) {
            for (let i = 0; i < (req.body.duree); i++) {
                montantRed += redevances[i].montant;
                //redevances[i].montant = redevances[i].abonnement.loyer;
                redevances[i].statut = "Payée";
                annne = redevances[i].annee;
                tableauDeRedevances.push(redevances[i]);
            }
        }
        // req.body["mode"]=2;
        const paiement = new Paiement()
        paiement.agence = req.body.agenceId;
        paiement.userCreation = req.body.userCreation;
        var montantRemise = 0
        //Calcul de la remise 
        if (campagne) {
            montantRemise = montantRed * ((campagne.taux) / 100);
            //    montantRed = montantRed - montantRemise;
            paiement.taux = campagne.taux;
        }

        if (montantPenalite > 0 && campagne) {
            //  montantRemise += montantPenalite  - montantPenalite * ((campagne) ? campagne.taux : 0)/100;
            montantPenalite = montantPenalite - montantPenalite * ((campagne) ? campagne.taux : 0) / 100;

        }

        montantRed = montantRed - montantRemise + montantPenalite;

        //Création d'un Paiement
        paiement.abonnement = abonnement;
        paiement.datePaiement = new Date();
        paiement.montantPaye = montantRed;
        paiement.montantRecu = montantRed;
        paiement.montantRemise = montantRemise;
        paiement.montantPenalite = montantPenalite;
        paiement.montantRestant = 0;
        paiement.duree = req.body.duree;
        paiement.modePaiement = req.body.mode;
        paiement.userCreation = req.body.userCreation;
        if (req.body.check && req.body.check.idTransaction) {
            paiement.transactionId = req.body.check.idTransaction;
        }
        if (req.params.type) {
            paiement.source = req.params.type
        }
        if (campagne) {
            paiement.campagne = campagne;
        }

        if (req.body.idTransaction) {
            paiement.transactionId = req.body.idTransaction;
        }
        resPaiement = await transactionalEntityManager.getRepository(Paiement).save(paiement)
        for (let j = 0; j < (tableauDeRedevances).length; j++) {
            tableauDeRedevances[j].paiement = resPaiement;
        }
        await transactionalEntityManager.getRepository(Redevance).save(tableauDeRedevances);
        const refsRedevances = await transactionalEntityManager.getRepository(Redevance)
            .createQueryBuilder("red")
            .leftJoinAndSelect("red.paiement", "paiement")
            .where("paiement.id = :id", { id: resPaiement.id })
            .select("red.refRedevance")
            .getMany();
        refs = refsRedevances.map((redevance) => redevance.refRedevance);

    }).then(async (redevances) => {
        const pdf = recuReabonnement(resPaiement.id, req, res);
        const abonne = resPaiement.abonnement.abonne;
        const data = {
            'userCreation': req.body.userCreation,
            'complementMessage': refs,
        }
        // envoie d'sms d'abonnement ici redevances est mis à la place du paiement par le return de la transaction
        abonne.telephone && replaceAndSend(2, resPaiement, abonne.telephone.replace(/\s/g, ''), data);
        //envoie de mail
        const subject = 'REABONNEMENT EFFECTUEE AVEC SUCCES REF : ' + resPaiement.refPaiement;
        abonne.email && sendEmail(2, subject, abonne.email, resPaiement, null, refs);

        return success(res, 201, { resPaiement, pdf }, "Paiement effectué avec succès");

    }).catch(error => {
        if (error instanceof ValidationError) {
            return generateServerErrorCode(res, 400, error, 'Cette redevance existe déjà')
        }
        if (error.code == "ER_DUP_ENTRY") {
            return generateServerErrorCode(res, 400, error, 'Cette redevance existe déjà')
        }
        const message = `Le paiement n'a pas pu être ajouté. Réessayez dans quelques instants.`;
        return generateServerErrorCode(res, 500, error, message);
    })
}

export const createPaiementRedevanceByIdRedeva = async (req: Request, res: Response) => {
    const tableauDeRedevances: Redevance[] = [];
    const idRedevs = req.body.check;
    for (let i = 0; i < (idRedevs).length; i++) {
        const redevance = await myDataSource.getRepository(Redevance).findOne({ where: { id: idRedevs[i], }, relations: { abonnement: true } });
        //Injection dans le tableau
        redevance.montant = redevance.abonnement.loyer;
        redevance.statut = "Payée";
        tableauDeRedevances.push(redevance);
    }
    await myDataSource.getRepository(Redevance).save(tableauDeRedevances)
        .then((tableauDeRedevances) => {
            //Creation du tableau de paiement
            const tableauDePaiements: Paiement[] = [];
            for (let j = 0; j < (tableauDeRedevances).length; j++) {
                //Création d'une redevance
                const paiement = new Paiement()
                //paiement.redevance = tableauDeRedevances[j];
                paiement.abonnement = tableauDeRedevances[j].abonnement;
                paiement.datePaiement = new Date();
                paiement.montantPaye = tableauDeRedevances[j].abonnement.montant;
                paiement.montantRecu = tableauDeRedevances[j].abonnement.montant;
                paiement.montantRestant = 0;
                paiement.agence = req.body.agenceId;
                paiement.userCreation = req.body.userCreation;
                paiement.modePaiement = req.body.mode;

                if (req.params.type) {
                    paiement.source = req.params.type
                }
                // Injection dans le tableau
                tableauDePaiements.push(paiement);
            }
            myDataSource.getRepository(Paiement).save(tableauDePaiements).then((tableauDePaiements) => {
                return success(res, 201, tableauDePaiements, "Les paiement ont bien réussi");
            }).catch(error => {
                if (error instanceof ValidationError) {
                    return generateServerErrorCode(res, 400, error, 'Ce paiement existe déjà')
                }
                if (error.code == "ER_DUP_ENTRY") {
                    return generateServerErrorCode(res, 400, error, 'Ce paiement existe déjà')
                }
                const message = `Le paiement n'a pas pu être ajouté. Réessayez dans quelques instants.`
                return generateServerErrorCode(res, 500, error, message)
            })
        }).catch(error => {
            if (error instanceof ValidationError) {
                return generateServerErrorCode(res, 400, error, 'Cette redevance existe déjà')
            }
            if (error.code == "ER_DUP_ENTRY") {
                return generateServerErrorCode(res, 400, error, 'Cette redevance existe déjà')
            }
            const message = `Le paiement n'a pas pu être ajouté. Réessayez dans quelques instants.`
            return generateServerErrorCode(res, 500, error, message)
        })
}

export const updatePaiement = async (req: Request, res: Response) => {
    const paiement = await myDataSource.getRepository(Paiement).findOneBy({ id: parseInt(req.params.id), })
    if (!paiement) {
        return generateServerErrorCode(res, 400, "L'id n'existe pas", 'Ce paiement existe déjà')
    }
    myDataSource.getRepository(Paiement).merge(paiement, req.body);
    const errors = await validate(paiement)
    if (errors.length > 0) {
        const message = validateMessage(errors);
        return generateServerErrorCode(res, 400, errors, message)
    }
    await myDataSource.getRepository(Paiement).save(paiement).then(Paiement => {
        const message = `Le paiement ${req.body.nom} a bien été modifié.`
        return success(res, 200, paiement, message);
    }).catch(error => {
        if (error instanceof ValidationError) {
            return generateServerErrorCode(res, 400, error, 'Ce paiement existe déjà')
        }
        if (error.code == "ER_DUP_ENTRY") {
            return generateServerErrorCode(res, 400, error, 'Ce paiement existe déjà')
        }
        const message = `Le paiement n'a pas pu être ajouté. Réessayez dans quelques instants.`
        return generateServerErrorCode(res, 500, error, message)
    })
}

export const deletePaiement = async (req: Request, res: Response) => {
    // const resultat = await checkRelationsOneToMany('Paiement', parseInt(req.params.id));
    await myDataSource.getRepository(Paiement).findOne({ where: { id: parseInt(req.params.id) }, relations: ['redevances'] }).then(paiement => {
        if (paiement === null) {
            const message = `Le paiement demandé n'existe pas. Réessayez avec un autre identifiant.`
            return generateServerErrorCode(res, 400, "L'id n'existe pas", message);
        }
        // if (resultat) {
        //     const message = `Ce paiement est lié à d'autres enregistrements. Vous ne pouvez pas le supprimer.`
        //     return generateServerErrorCode(res, 400, "Ce paiement est lié à d'autres enregistrements. Vous ne pouvez pas le supprimer.", message);
        // } else {
            //
            // myDataSource.getRepository(Paiement).softRemove(paiement)
            paiement.statut = "Annulé";
            paiement.redevances.forEach(redevance => {
                redevance.statut = "En attente";
                redevance.paiement = null;
            });
            myDataSource.getRepository(Paiement).save(paiement);
            myDataSource.getRepository(Redevance).save(paiement.redevances)
            .then(_ => {
                const message = `Le paiement avec l'identifiant n°${paiement.id} a bien été supprimé.`;
                return success(res, 200, paiement, message);
            })
        // }
    }).catch(error => {
        const message = `Le paiement n'a pas pu être supprimé. Réessayez dans quelques instants.`
        return generateServerErrorCode(res, 500, error, message)
    })
}

export const operationPeriode = async (req: Request, res: Response) => {

    const dateDebut = new Date(req.query.dateDebut as string);
    const dateFin = new Date(req.query.dateFin as string);
    console.log("dateDebut", dateDebut);
    console.log("dateFin", dateFin);

    if (!dateDebut || !dateFin) {
        const message = `Les dates de début et de fin sont requises.`
        return generateServerErrorCode(res, 400, "Champs vide", message)
    }
    
    let reque = await myDataSource.getRepository(Paiement)
        .createQueryBuilder("paiement")
        .select([
            "paiement.refPaiement", 
            "paiement.montantPaye", 
            "paiement.montantRemise",
            "paiement.montantPenalite", 
            "paiement.datePaiement", 
            "paiement.source",
            "paiement.duree",
            "abonnement.refAbo",
            "abonnement.loyer",
            "abonne.nomComplet",
            "boitePostale.newAdressePostale",
            "modele.code",
            "service.libelle",
        ])
        .leftJoin("paiement.abonnement", "abonnement")
        .leftJoin("paiement.service", "service")
        .leftJoin("abonnement.boite", "boitePostale")
        .leftJoin("boitePostale.modele", "modele")
        .leftJoin("paiement.demande", "demande")
        .leftJoin("abonnement.abonne", "abonne")
        .where("paiement.datePaiement >= :dateDebut AND paiement.datePaiement <= :dateFin", { dateDebut, dateFin })
        .getMany()
    .then(paiements => {
        if (paiements === null) {
            const message = `Aucun élément ne correspond à votre recherche.`
            return generateServerErrorCode(res, 400, "Aucun élément ne correspond à votre recherche", message)
        }
        const message = `La récupération a bien été exécuté.`
        return success(res, 200, paiements, message);
    })
    .catch(error => {
        const message = `Aucune paiement n'a pas pu être récupéré faute d'une erreur . Réessayez dans quelques instants.`
        return generateServerErrorCode(res, 500, error, message)
    })
}
