import { Abonnement } from "../entity/Abonnement"
import { Redevance } from "../entity/Redevance"
import { myDataSource } from "../../../configs/data-source";
import { generateServerErrorCode, success, validateMessage } from "../../../configs/response";
import { Transfert } from "../../gestiondestransferts/entity/Transfert";
import { NextFunction, Request, Response } from "express";
import { ValidationError, isArray, validate } from "class-validator";
import { BoitePostale } from './../../gestiondesboites/entity/BoitePostale';
import { paginationAndRechercheInit } from "../../../configs/paginationAndRechercheInit";
import { Abonne } from "../../gestiondesabonnets/entity/Abonne";
import { Brackets } from 'typeorm';
import { Paiement } from "../../gestiondespaiements/entity/Paiement";
import { ModePaiement } from "../../gestiondespaiements/entity/ModePaiement";
import { Bureau } from "../../gestiondesagences/entity/Bureau";
import { Demande } from "../../gestiondesdemandes/entity/Demande";
import { checkRelationsOneToMany } from "../../../configs/checkRelationsOneToManyBeforDelete";
import { replaceAndSend } from "../../gestiondesnotifications/controller/envoieSMS";
import { checkRole } from "../../function.ts/function";
import { sendEmail } from "../../gestiondesnotifications/controller/envoieMail";
import { SendCodeOtp } from "../../gestionotp/controller/code.controller";
import { verificationOtp } from "../../../configs/sendSms";
import { docRedevanceHtml, recuAbonnement } from "../../gestiondesattestations/controller/document.controller";
import { Campagne } from "../../gestiondescampagnes/entity/Campagne";
import { genererRedevancesTempon } from "./redevance.controller";

export const createAbonnement = async (req: Request, res: Response) => {
    let abonnementReturn : Abonnement | Abonnement[];
    req.body["dureeReabonnement"] = (req.body.dureeAbonnement);
    if(req.params.type){
        req.body["source"]= req.params.type
    }
    
    if(req.body.etat == '' || req.body.etat == null){
        req.body["etat"] = 'Actif';
    }

    const abonnement = myDataSource.getRepository(Abonnement).create(req.body);

    const errors = await validate(abonnement)
    if (errors.length > 0) {
        const message = validateMessage(errors);
        return generateServerErrorCode(res,400,errors,message)
    }
    const nabon = await myDataSource.getRepository(Abonnement)
    .createQueryBuilder('a')
    .innerJoinAndSelect("a.boite","b")
    .where("b.id= :bid",{ bid: req.body.boite})
    .andWhere("(b.etat= :betat OR a.etat= :aetat)",{ betat: "Louée",  aetat: "Actif"})
    .getCount();

    if(nabon > 0) {
        const message= "La boîte postale n'est pas libre ou un abonnement existe avec la boîte";
        return generateServerErrorCode(res,400,'Un adresse existe déjà avec ce numéro de téléphone',message);
    }
    
    // if(req.body.numVerify == false) {
    //    const data =  await verificationOtp(req.body)
    //     if(data){
    //         if(data.status == "approved") {
    //             myDataSource.getRepository(Abonne).createQueryBuilder()
    //             .update({ verifyNumber:true })
    //             .where("id = :AbonneId", { AbonneId: req.body.abonne })
    //             .execute();
    //         } else {
    //             return generateServerErrorCode(res,400,"","L’utilisateur n'a pas été vérifié!")
    //         }
    //     }else{
    //         return generateServerErrorCode(res,400,"","Le code OTP n'est pas correcte, veuillez rééssayer")
    //     }
    // }
    
    var paiem = null;
    var tabRedevances = null;

    await myDataSource.manager.transaction(async (transactionalEntityManager) => {
        const abo: Abonnement | Abonnement[] = await transactionalEntityManager.save(abonnement);
        let aboWithRelation:Abonnement = null;
        
       
        abonnementReturn = abo;
        var av = null;
        var boitePostale;
        var abonne;
        var categorieAbonne;
        if(!isArray(abo)) {
            const aboSingle = abo as Abonnement;
            aboWithRelation = await transactionalEntityManager.getRepository(Abonnement).findOne(
                {
                    where:{
                        id:aboSingle.id
                    },
                    relations:{
                        abonne:{  categorieAbonne:true }
                    }
                }
            );
            //roleId = abo[0].id
            // } else {
            const resultrol = abo as Abonnement
             boitePostale = resultrol.boite;
             abonne = resultrol.abonne;
             categorieAbonne = (aboWithRelation.abonne.categorieAbonne) ? aboWithRelation.abonne.categorieAbonne : 0;
             av = resultrol;
        }

        await transactionalEntityManager.getRepository(BoitePostale).createQueryBuilder()
        .update({etat:"Louée",estOfficiel: req.body.typeBoite, userCreation: req.body.userCreation})
        .where("id = :boitePostalId", { boitePostalId: boitePostale })
        .execute();

        await transactionalEntityManager.getRepository(Abonne).createQueryBuilder()
        .update({estAbonne:true, userCreation: req.body.userCreation})
        .where("id = :abonneId", { abonneId: abonne })
        .execute();

        const tabRedevance:Redevance[] = [];
        const dateActuelle: Date = new Date();
        var annee:number;

        //Recheche d'une campagne
        let campagne = null;
        let laDate = new Date();
        let montantRemise = 0;

        campagne = await myDataSource.getRepository(Campagne)
        .createQueryBuilder("c")
        .where("c.typeDeCampagne = :rem",{rem:"Reduction"})
        .andWhere(":ladate BETWEEN c.dateDebut AND c.dateFin",{ladate:laDate});
        if(categorieAbonne && categorieAbonne != 0){ 
            campagne.andWhere("(c.categorieAbonne = :categorieAbonneId)",{categorieAbonneId:categorieAbonne.id});
        }
        campagne = await campagne.orderBy("c.id","DESC").limit(1).getOne();
        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();
        }
        

        const paiement = new Paiement();
        paiement.abonnement = av;
        paiement.montantPaye = req.body.montant;
        paiement.userCreation = req.body.userCreation;
        paiement.montantPaye = req.body.montant;
        paiement.duree = req.body.dureeAbonnement;
        if(req.body.idTransaction){
            paiement.transactionId = req.body.idTransaction ;
        }

        if(campagne){
            // montantRemise = (av.loyer * av.dureeReabonnement) * ((campagne.taux)/100);
            montantRemise = (((av.dureeReabonnement -1) * av.loyer) + av.loyerAnneeEncours) * campagne.taux / 100;
            paiement.taux = campagne.taux;
            paiement.montantRemise = montantRemise;
            paiement.campagne = campagne;
        }

        if(req.params.type){
            paiement.source= req.params.type
        }
        if(req.body.check && req.body.check.idTransaction){
            paiement.transactionId = req.body.check.idTransaction; 
        }
        
        paiement.modePaiement =  await myDataSource.getRepository(ModePaiement).findOne({where:{id:req.body.mode}});
        paiement.datePaiement = new Date();
        const paie = await transactionalEntityManager.getRepository(Paiement).save(paiement);
        paiem = paie;
        annee = dateActuelle.getFullYear();
        if(req.body.dureeAbonnement >= 1){
            const incr:number = Date.now(); 
            for(let i = 0;i < (req.body.dureeAbonnement); i++){
                const redevance = new Redevance();
                redevance.montant = av.loyer;
                redevance.refRedevance= 'RE'+(incr+1);  
                redevance.paiement = paiement;
                redevance.abonnement = av;
                redevance.userCreation = req.body.userCreation;
                redevance.agence = req.body.agence;
                redevance.annee = annee;
                redevance.statut = "Payée";
                tabRedevance.push(redevance);
                annee++;
            }
          tabRedevances =  await transactionalEntityManager.getRepository(Redevance).save(tabRedevance);
        }
    })
    .then(async(abo_) => {
        if(!Array.isArray(abonnementReturn)){
            
            const mon_abonne = await myDataSource.getRepository(Abonne).findOne({where: {id: Number(abonnementReturn.abonne)}});
            // envoie d'sms d'abonnement
            if (mon_abonne.telephone) {
                const sms = replaceAndSend(5, abonnementReturn, mon_abonne.telephone.replace(/\s/g, ''));
            }
            // envoie de mail d'abonnement
            const subject = 'BIENVENUE DANS NOTRE GRANDE FAMILLE';
            mon_abonne.email && sendEmail(5,subject, mon_abonne.email, abonnementReturn);

        }
        // generation du reçu de paiement
         await recuAbonnement(paiem.id,req);
        //  await recuAbonnement(paiem.id,req,res);

        for(let i = 0; i < tabRedevances.length; i++){
            await docRedevanceHtml(tabRedevances[i].id,req,res);
        }
        const message = `L'abonnement a bien été crée.`
        return success(res,201, {abo_ , paiem},message);
    })
    .catch(error => {
        if(error instanceof ValidationError) {
            return generateServerErrorCode(res,400,error,'Tous les champs obligatoire ne sont pas renseignés')
        }
        if(error.code == "ER_DUP_ENTRY") {
            return generateServerErrorCode(res,400,error,'Cet abonnement existe déjà')
        }
        const message = `L'abonnement n'a pas pu être ajouté. Réessayez dans quelques instants.`
        console.log(error,"errorerrorerrorerrorerror");
        return generateServerErrorCode(res,500,error,message);
    })
}

// export const verifyMpostBoxNumber = async (req: Request, res: Response) => {
//     const  numero  = req.query.numero as string;
//     const abon = await myDataSource.getRepository(Abonnement).findOne({
//         where: {
//             numero: numero,
//             estMPostBox: true
//         }
//     });

//     if(abon) {
//         const message= "Un adresse existe déjà avec ce numéro de téléphone";
//         const data = {existe:true}
//         return success(res,200, data ,message);
//     }
// }

export const verifyMpostBoxNumber = async (req: Request, res: Response) => {
    try {
        const { numero, bureauId } = req.body;
        if(numero) {
            const abon = await myDataSource.getRepository(Abonnement).findOne({
                where: {
                    numero: numero,
                    estMPostBox: true
                }
            });
        
            if(abon) {
                const message= "Un adresse existe déjà avec ce numéro de téléphone";
                const data = {existe:true}
                return generateServerErrorCode(res,400,'Un adresse existe déjà avec ce numéro de téléphone',message);
            }
            console.log(abon,bureauId,'888888888888888888888888888');
        }
        
       const bureau = await myDataSource.getRepository(Bureau).findOne({
            where:{
                id: parseInt(bureauId)
            },
            relations:{
                commune:true,
            },
        })

        if(bureau === null) {
            const message = `Le bureau demandée n'existe pas. Réessayez avec un autre identifiant.`
            return generateServerErrorCode(res,400,"L'id n'existe pas",message)
        }
        const message = `Le bureau a bien été trouvé.`
        return success(res,200, bureau,message);
        
    } catch (error) {
        const message = `Le bureau n'a pas pu être récupéré. Réessayez dans quelques instants.`
        return generateServerErrorCode(res,500,error,message)
    }
}

export const createMpostBox = async (req: Request, res: Response) => {
    
    const { adresseVirtuelle, numero, loyer, bureau, abonne } = req.body;
    if(!adresseVirtuelle || !numero || !loyer || !bureau || !abonne) {
        const message = 'Tous les champs obligatoiree ne sont pas renseigner';
        return generateServerErrorCode(res,400, req.body,message)
    }
    req.body.numero = req.body.numero.replace(/\s/g, '');

    const abon = await myDataSource.getRepository(Abonnement).findOne({
        where: {
            numero: numero,
            estMPostBox: true
        }
    });

    if(abon) {
        const message= "Un adresse existe déjà avec ce numéro de téléphone";
        return generateServerErrorCode(res,400, req.body,message)
    }


    if(req.body.etat == '' || req.body.etat == null){
        req.body["etat"] = 'Actif';
    }
    req.body['estMPostBox'] = true;
    req.body["montant"] = req.body.loyer;

    if(req.body.abonnement){
        req.body["abonnement"] = req.body.abonnement;
    }
    const abonnement = myDataSource.getRepository(Abonnement).create(req.body);
    var paie:Paiement;

    await myDataSource.manager.transaction(async (transactionalEntityManager) => {
       const abo = await transactionalEntityManager.getRepository(Abonnement).save(abonnement)
       var av = null;

        if(isArray(abo)) {
            // roleId = abo[0].id
        } else {
            const resultrol = abo as Abonnement;
            av = resultrol;
            var abonne = resultrol.abonne;
        }
        const paiement = new Paiement();
        paiement.abonnement = av;
        if(req.body.check && req.body.check.idTransaction){
            paiement.transactionId = req.body.check.idTransaction; 
        }

        if(req.body.idTransaction){
            paiement.transactionId = req.body.idTransaction; 
        }
       // paiement.transactionId = req.body.idTransaction;
        paiement.montantPaye = req.body.loyer;
        paiement.modePaiement = req.body.mode;
        var transfert;
        paie = await transactionalEntityManager.getRepository(Paiement).save(paiement);
        await transactionalEntityManager.getRepository(Abonne).createQueryBuilder()
        await transactionalEntityManager.getRepository(Abonne).createQueryBuilder()
        .update({estAbonne:true})
        .where("id = :abonneId", { abonneId: abonne })
        .execute();
        if(req.body.demande){
            await transactionalEntityManager.getRepository(Transfert).save(transfert);
           const demande = await transactionalEntityManager.getRepository(Demande).createQueryBuilder()
            .update({status:  "Validée"})
            .where("id = :demId", { demId: req.body.demande })
            .execute();
        }
        return abonnement;
    }).then(async(abo) => {
        //Génération du document de paiement MPOSBOX
        // if(!Array.isArray(paie)){
        //     await recuPaiementHtml(paie.id,req,res);
        // }
        // envoie d'sms d'abonnement mpostbox
        const sms = replaceAndSend(17, abo, req.body.numero.replace(/\s/g, ''));
        const message = `L'abonnement a bien été crée.`;
        return success(res,201, {abo, paie},message);
    })
    .catch(error => {
        if(error instanceof ValidationError) {
            return generateServerErrorCode(res,400,error,'Cet abonnement existe déjà')
        }
        if(error.code == "ER_DUP_ENTRY") {
            return generateServerErrorCode(res,400,error,'Cet abonnement existe déjà')
        }
        const message = `L'abonnement n'a pas pu être ajouté. Réessayez dans quelques instants.`
        return generateServerErrorCode(res,500,error,message)
    })
}


export const createMpostBoxTransfert = async (req: Request, res: Response) => {
    const { adresseVirtuelle, numero, loyer, bureau, abonne } = req.body;
    if(!adresseVirtuelle || !numero || !loyer || !bureau || !abonne) {
        const message = 'Tous les champs obligatoiree ne sont pas renseigner';
        return generateServerErrorCode(res,400, req.body,message)
    }
    req.body.numero = req.body.numero.replace(/\s/g, '');

    console.log('req.body.numero ===> ', (req.body.numero).replace(/\s/g, ''));
    //
    var abon = await myDataSource.getRepository(Abonnement)
    .createQueryBuilder("a")
    .where("a.estMPostBox = 1")
    .andWhere("a.numero = :numero",{numero:(req.body.numero).replace(/\s/g, '')})
    .getOne();

    var abonnement;

    if(abon == null){
        if(req.body.etat == '' || req.body.etat == null){
            req.body["etat"] = 'Actif';
        }
        req.body['estMPostBox'] = true;
        req.body["montant"] = req.body.loyer;
        abonnement = await myDataSource.getRepository(Abonnement).create(req.body);
    }
    
    await myDataSource.manager.transaction(async (transactionalEntityManager) => {
        var abo;
        var av = null;
        var abonne;

        if(abon == null){
            abo = await transactionalEntityManager.getRepository(Abonnement).save(abonnement)
            if(isArray(abo)) {
                // roleId = abo[0].id
            } else {
                const resultrol = abo as Abonnement;
                av = resultrol;
                abonne = resultrol.abonne;
            }
        }else{
            if(isArray(abon)) {
                // roleId = abo[0].id

            } else {
                const resultrol = abon as Abonnement;
                av = resultrol;
                abonne = resultrol.abonne;
            }
        }

        const paiement = new Paiement();
        paiement.abonnement = av;
        if(req.body.check && req.body.check.idTransaction){
            paiement.transactionId = req.body.check.idTransaction; 
        }

        if(req.body.idTransaction){
            paiement.transactionId = req.body.idTransaction; 
        }
       // paiement.transactionId = req.body.idTransaction;
        paiement.montantPaye = req.body.loyer;
        paiement.modePaiement = req.body.mode;
        var transfert;
        const abonn = await transactionalEntityManager.getRepository(Abonnement).findOne({
            where:{
                id:req.body.abonnement
            },
            relations:{
                bureau:true,
                boite:{
                    bureau:true,
                }
            }
        });
        // console.log("5")
        // console.log("ABONNEMENT  44 ",abonn ); 
        //     //Insertion des information du transfert
        //     req.body["nouvelleAgence"] = req.body.bureau;
        //     console.log("7")
        //     req.body["ancienneAgence"] = abonn.boite ? abonn.boite.bureau.id : abonn.bureau.id;
        //     console.log("8")
        //     req.body["boite"] = abonn.boite ? abonn.boite.id : null;
        //     console.log(req.body["nouvelleAgence"],req.body["ancienneAgence"], req.body["boite"] )
        //     if(req.body.adresseVirtuelle){
        //         req.body["mpostbox"] = req.body.abonnement;
        //     }
        //     console.log("REQUERTTETTET ", req.body)
        //     const transfert1 = myDataSource.getRepository(Transfert).create(req.body);
        //     transfert = transfert1;

        //     console.log("transfert1 ===>", transfert1)
        //     console.log("transfert ===> ", transfert)
        //     console.log("paiement ===> ", paiement)
        //Insertion des information du transfert
        req.body["nouvelleAgence"] = req.body.bureau;
        req.body["ancienneAgence"] = abonn.boite ? abonn.boite.bureau.id : abonn.bureau.id;
        req.body["boite"] = abonn.boite ? abonn.boite.id : null;
        console.log(req.body["nouvelleAgence"],req.body["ancienneAgence"], req.body["boite"] )
        if(req.body.adresseVirtuelle){
            req.body["mpostbox"] = req.body.abonnement;
        }
        const transfert1 = myDataSource.getRepository(Transfert).create(req.body); //new Transfert();
        transfert = transfert1;
        
        await transactionalEntityManager.getRepository(Paiement).save(paiement);
        await transactionalEntityManager.getRepository(Abonne).createQueryBuilder()
        .update({estAbonne:true})
        .where("id = :abonneId", { abonneId: abonne })
        .execute();
        await transactionalEntityManager.getRepository(Transfert).save(transfert);
        const demande = await transactionalEntityManager.getRepository(Demande).createQueryBuilder()
        .update({status:  "Validée"})
        .where("id = :demId", { demId: req.body.demande })
        .execute();

        if(!abon){
            await transactionalEntityManager.getRepository(Abonnement).createQueryBuilder()
            .update({bureau: req.body.bureau, etat:"Transféré"})
            .where("id = :id", { id: req.body.abonnement })
            .execute();
            console.log("La modification ABONNEMENT est faite");
        }else{
            await transactionalEntityManager.getRepository(Abonnement).createQueryBuilder()
            .update({bureau: req.body.bureau, etat:"Transféré"})
            .where("id = :id", { id: av.id })
            .execute();
            console.log("La modification MPOST est faite");
        }


        return abonnement;
    }).then(abo => {
        // envoie d'sms d'abonnement mpostbox
        const sms = replaceAndSend(17, abo, req.body.numero.replace(/\s/g, ''));
        const message = `L'abonnement a bien été crée.`;
        return success(res,201, abo,message);
    })
    .catch(error => {
        if(error instanceof ValidationError) {
            return generateServerErrorCode(res,400,error,'Cet abonnement existe déjà')
        }
        if(error.code == "ER_DUP_ENTRY") {
            return generateServerErrorCode(res,400,error,'Cet abonnement existe déjà')
        }
        const message = `L'abonnement n'a pas pu être ajouté. Réessayez dans quelques instants.`
        return generateServerErrorCode(res,500,error,message)
    })
}



export const getAllAbonnements = async (req: Request, res: Response,next:NextFunction) => {
    const bureau = req.query.bureau;
    const categorieAbonne = req.query.categorieAbonne;
    const modele = req.query.modeleBoite;
    const etat = req.query.etat;
    // const { page, limit, searchTerm, startIndex, searchQueries } = paginationAndRechercheInit(req, Abonnement);
    const page = parseInt(req.query.page as string) || 1;
    const limit = parseInt(req.query.limit as string) || 10;
    const searchTerm = req.query.mot as string || '';
    const startIndex = (page - 1) * limit;
    let searchQueries = [];
    
    let reque = await myDataSource.getRepository(Abonnement)
        .createQueryBuilder("abonnement")
        .innerJoinAndSelect("abonnement.abonne", "abonne")
        .innerJoinAndSelect("abonnement.boite", "boitePostale")
        .leftJoinAndSelect("abonnement.bureau", "bureau")
        // .leftJoinAndSelect("abonnement.quartier", "quartier")
        .leftJoinAndSelect("boitePostale.bureau", "agence")
        // .leftJoinAndSelect("abonnement.tarif", "tarifAnnuel")
        .leftJoinAndSelect("boitePostale.adressePostale", "adressePostale")
        .leftJoinAndSelect("boitePostale.modele", "modelBoite")
        .leftJoinAndSelect("abonne.categorieAbonne","cate")
        // .leftJoinAndSelect("abonne.activite","secte")
        // .where(searchQueries.join(' OR '), { keyword: `%${searchTerm}%` })
        .where("abonnement.estMPostBox = 0");
        if(bureau != '') {
            reque.andWhere("bureau.id = :bid", { bid: bureau });
        }
        const donnee:boolean = await checkRole(req);
        if(donnee == false){
            if(req.body.agenceId){
                reque.andWhere("(bureau.id =:bureau OR agence.id = :bureau)",{bureau: parseInt(req.body.agenceId)});
            }
        }
        if(categorieAbonne != '') {
            reque.andWhere("cate.id = :cid", { cid: categorieAbonne });
        }
        if(modele != '') {
            reque.andWhere("modelBoite.id = :caid", { caid: modele });
        }
        if(etat != '') {
            reque.andWhere("abonnement.etat = :et", { et: etat });
        }
        if(searchTerm && searchTerm !== '') {
            const st = searchTerm.split(/\s+/); // découpage
            reque.andWhere(
                new Brackets(qb => {
                    st.forEach((term, index) => {
                        const paramName = `keyword${index}`;
                        qb.andWhere(
                            new Brackets(subQb => {
                                subQb.where(`(
                                    abonne.nomComplet LIKE :${paramName}
                                    OR abonnement.refAbo LIKE :${paramName}
                                    OR abonnement.dateAbonnement LIKE :${paramName}
                                    OR adressePostale.adresse_postale LIKE :${paramName}
                                    OR abonnement.etat LIKE :${paramName}
                                    OR modelBoite.libelle LIKE :${paramName}
                                    OR cate.libelle LIKE :${paramName}
                                    OR bureau.nom LIKE :${paramName}
                                )`, { [paramName]: `%${term}%` });
                            })
                        );
                    });
                })
            );
        }
        reque.andWhere("abonnement.deletedAt IS NULL")
        .orderBy(`abonnement.id`, 'DESC')
        .skip(startIndex)
        .take(limit)
        .getManyAndCount()
    .then(async ([data, totalElements]) => {
        // const totalElements = data.length;
        // const totalElements = await myDataSource.getRepository(Abonnement)
        // .createQueryBuilder("abonnement")
        // .where("abonnement.deletedAt IS NULL")
        // .getCount();
        const message = 'La liste des Abonnements a bien été récupéré.';
        const totalPages = Math.ceil(totalElements / limit);
        return success(res,200,{data, totalPages, totalElements, limit}, message);
    }).catch(error => {
        const message = `La liste des Abonnements n'a pas pu être récupéré. Réessayez dans quelques instants.`
        return generateServerErrorCode(res,500,error,message)
    })
};

export const sendCode = async (req: Request, res: Response) => {
    try {
        console.log(req.body.telephone);
        const response = await SendCodeOtp(req.body)
        console.log("Response ==>)", response);
        if(response.data.status == "pending"){
            return success(res,200,req.body,"Le code de vérification est envoyé avec succès"+req.body.telephone)
        } else {
            return generateServerErrorCode(res,400,response['data'],response['message'])
        }
    } catch (error) {
        const message = "Le code n'a pas pu être envoyé. Vérifiez si vous êtes connecté à internet et réessayer."
       // return { status:500,message:"Le code n'a pas pu être ajouté. Réessayez dans quelques instants.",data:{status:"fail",message:""} }
        return generateServerErrorCode(res,400,error,message)
    }
}


export const getMpostAbonnements = async (req: Request, res: Response) => {
    const { page, limit, searchTerm, startIndex, searchQueries } = paginationAndRechercheInit(req, Abonnement);
    let reque = await myDataSource.getRepository(Abonnement)
        .createQueryBuilder("abonnement")
        .leftJoinAndSelect("abonnement.boite","boitePostale")
        .leftJoinAndSelect("abonnement.tarif","tarifAnnuel")
        .leftJoinAndSelect("boitePostale.adressePostale", "adressePostale")
        .leftJoinAndSelect("abonnement.abonne","abonne")
        .leftJoinAndSelect("abonnement.bureau","bureau")
        .leftJoinAndSelect("abonnement.quartier","quartier")
        .where("abonnement.deletedAt IS NULL")
        .andWhere("abonnement.estMPostBox = 1");
        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)",{bureau: parseInt(req.body.agenceId)});
            }
        }
        reque.orderBy(`abonnement.id`, 'DESC')
        .skip(startIndex)
        .take(limit)
        .getManyAndCount()
    .then(([data, totalElements]) => {
        const message = 'La liste des Abonnements a bien été récupéré.';
        const totalPages = Math.ceil(totalElements / limit);
        return success(res,200,{data, totalPages, totalElements, limit}, message);
    }).catch(error => {
        const message = `La liste des Abonnements n'a pas pu être récupéré. Réessayez dans quelques instants.`
        return generateServerErrorCode(res,500,error,message)
    })
};

export const getAllAbonnementMPostBox = async (req: Request, res: Response) => {
    const { page, limit, searchTerm, startIndex, searchQueries } = paginationAndRechercheInit(req, Abonnement);
    let reque = await myDataSource.getRepository(Abonnement)
        .createQueryBuilder("abonnement")
        .innerJoinAndSelect("abonnement.abonne", "abonne")
        .leftJoinAndSelect("abonnement.boite", "boitePostale")
        .leftJoinAndSelect("boitePostale.adressePostale", "adressePostale")
        .leftJoinAndSelect("abonnement.bureau","bureau")
        .leftJoinAndSelect("abonnement.quartier","quartier")
        .leftJoinAndSelect("boitePostale.bureau", "agence")
        .where("abonne.id = :key", { key: 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)",{bureau: parseInt(req.body.agenceId)});
            }
        }
        reque.andWhere("abonnement.deletedAt IS NULL")
        .andWhere("abonnement.etat != :etat1",{etat1:"En attente"})
        .andWhere("abonnement.etat != :etat2",{etat2:"Résilié"})
        .skip(startIndex)
        .take(limit)
        .getManyAndCount()
    .then(([data, totalElements]) => {
        const message = 'La liste des abonnements a bien été récupéré.';
        const totalPages = Math.ceil(totalElements / limit);
        return success(res,200,{data, totalPages, totalElements, limit}, message);
    }).catch(error => {
        const message = `La liste des abonnements n'a pas pu être récupéré. Réessayez dans quelques instants.`
        return generateServerErrorCode(res,500,error,message)
    })
    
};
  
export const getAbonnementByAbonne = async (req: Request, res: Response) => {
    if(!req.body.abonne){
        return generateServerErrorCode(res,500,req.body,"Aucun abonné connecté")
    }
    await (myDataSource.getRepository(Abonnement)
        .createQueryBuilder("a")
        .leftJoinAndSelect("a.boite", "b")
        .leftJoinAndSelect("b.adressePostale", "adressePostale")
        .innerJoinAndSelect("a.abonne", "ab")
        .where("ab.id like :key1", { key1: `%${req.body.abonne}%` })
        .andWhere("a.estResilier != 1")
        .andWhere("a.deletedAt IS NULL")
        .orderBy("a.id","DESC")
        .getMany()).
    then(abonnements => {
        if(abonnements === null) {
          const message = `Les abonnement de cet Abonné n'existe pas. Réessayez avec un autre identifiant.`
          return generateServerErrorCode(res,400,"L'id n'existe pas",message)
        }
        const message = `La liste des abonnements a bien été récupéré.`
        return success(res,200, abonnements,message);
    })
    .catch(error => {
        const message = `Les abonnement n'ont pas pu être récupérés. Réessayez dans quelques instants.`
        return generateServerErrorCode(res,500,error,message)
    })
};

export const getAbonnement = async (req: Request, res: Response) => {
    await myDataSource.getRepository(Abonnement).findOne({
        where: {
            id: parseInt(req.params.id),
        },
        relations: {
            boite:{
                adressePostale:true,
                modele:true,
            },
            abonne:{
                categorieAbonne:true,
                activite:true,
            },
          //  adressePostale:true,
            transferts:{
                boite:{
                    modele:true,
                    adressePostale:true,
                },
                nouvelleAgence:true,
                ancienneAgence:true,
            },
            bureau:true,
            quartier:{
                arrondissement:true,
            }    
        }
    }).
    then(abonnement => {
        if(abonnement === null) {
          const message = `L'abonnement demandé n'existe pas. Réessayez avec un autre identifiant.`
          return generateServerErrorCode(res,400,"L'id n'existe pas",message)
        }
        if (req.body.abonne ) {
            if (req.body.abonne && abonnement.abonne.id != req.body.abonne) {
                return generateServerErrorCode(res,400,"L'abonnement demandé n'est pas inclus dans vos abonnements.","L'abonnement demandé n'est pas inclus dans vos abonnements.")
            }
        }
        const message = `L'abonnement a bien été trouvé.`
        return success(res,200, abonnement,message);
    })
    .catch(error => {
        const message = `L'abonnement n'a pas pu être récupéré. Réessayez dans quelques instants.`
        return generateServerErrorCode(res,500,error,message)
    })
};

export const getAbonnementSuivi = async (req: Request, res: Response) => {
    await myDataSource.getRepository(Abonnement).findOne({
        where: {
            id: parseInt(req.params.id),
        },
        relations: {
            boite:{
                adressePostale:true,
                modele:true,
            },
            abonne:{
                categorieAbonne:true,
                activite:true,
            },
          //  adressePostale:true,
            transferts:{
                boite:{
                    modele:true,
                    adressePostale:true,
                },
                nouvelleAgence:true,
                ancienneAgence:true,
            },
            bureau:true,
            abonnement:{
                boite:{
                    modele:true,
                    adressePostale:true,
                },
                abonne:{
                    categorieAbonne:true,
                    activite:true,
                },
                bureau:true,
                transferts:{
                    boite:{
                        modele:true,
                        adressePostale:true,
                    },
                    nouvelleAgence:true,
                    ancienneAgence:true,
                
                },
            },
        }
    }).
    // await myDataSource.getRepository(Abonnement)
    // .createQueryBuilder("abonnement")
    // .leftJoinAndSelect("abonnement.boite", "boite")
    // .leftJoinAndSelect("boite.adressePostale", "adressePostale")
    // .addSelect(["boite.refBoite"])
    // .addSelect(["adressePostale.adresse_postale"])
    // .leftJoinAndSelect("abonnement.abonne", "abonne")
    // .leftJoinAndSelect("abonne.categorieAbonne", "categorieAbonne")
    // .leftJoinAndSelect("abonne.activite", "secteurActivite")
    // .addSelect(["categorieAbonne.libelle", "abonne.activite", "secteurActivite.libelle"])
    // .leftJoinAndSelect("abonnement.transferts", "transferts")
    // .addSelect(["transferts.boite.modele", "transferts.boite.adressePostale", "transferts.nouvelleAgence", "transferts.ancienneAgence"])
    // .leftJoinAndSelect("abonnement.bureau", "bureau")
    // .where("abonnement.id = :id", { id: parseInt(req.params.id) })
    // .getOne().
    then(abonnement => {
        if(abonnement === null) {
          const message = `L'abonnement demandé n'existe pas. Réessayez avec un autre identifiant.`
          return generateServerErrorCode(res,400,"L'id n'existe pas",message)
        }
        const message = `L'abonnement a bien été trouvé.`
        return success(res,200, abonnement,message);
    })
    .catch(error => {
        const message = `L'abonnement n'a pas pu être récupéré. Réessayez dans quelques instants.`
        return generateServerErrorCode(res,500,error,message)
    })
};

export const updateAbonnement = async (req: Request, res: Response) => {
    const abonnement = await myDataSource.getRepository(Abonnement).findOne(
    { 
        where: {
            id: parseInt(req.params.id),
        },
        relations: {
            boite: {
                adressePostale:true,
            },
            abonne:true,
            quartier:true,   
        },
    })
    if(!abonnement) {
        return generateServerErrorCode(res,400,"L'id n'existe pas",'Cet abonnement existe déjà')
    }
    myDataSource.getRepository(Abonnement).merge(abonnement,req.body);
    const errors = await validate(abonnement);
    if (errors.length > 0) {
        const message = validateMessage(errors);
        return generateServerErrorCode(res,400,errors,message)
    }
    await myDataSource.getRepository(Abonnement).save(abonnement).then(Abonnement => {
        const message = `L'abonnement ${abonnement.refAbo} a bien été modifié.`
        return success(res,200, Abonnement,message);
    }).catch(error => {
        if(error instanceof ValidationError) {
            return generateServerErrorCode(res,400,error,'Cet abonnement existe déjà')
        }
        if(error.code == "ER_DUP_ENTRY") {
            return generateServerErrorCode(res,400,error,'Cet abonnement existe déjà')
        }
        const message = `L'abonnement n'a pas pu être ajouté. Réessayez dans quelques instants.`
        return generateServerErrorCode(res,500,error,message)
        // res.status(500).json({ message, data: error }) 
    })
}
  
export const deleteAbonnement = async (req: Request, res: Response) => {
    const resultat = await checkRelationsOneToMany('Abonnement', parseInt(req.params.id));
    await myDataSource.getRepository(Abonnement).findOneBy({
        id: parseInt(req.params.id)
    }).then(abonnement => {        
        if(abonnement === null) {
          const message = `L'abonnement 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 abonnement est lié à d'autres enregistrements. Vous ne pouvez pas le supprimer.`
            return generateServerErrorCode(res,400,"Ce abonnement est lié à d'autres enregistrements. Vous ne pouvez pas le supprimer.",message);
        }else{
            myDataSource.getRepository(Abonnement).softRemove(abonnement)
            .then(_ => {
                const message = `L'abonnement avec l'identifiant n°${abonnement.refAbo} a bien été supprimé.`;
                return success(res,200, abonnement,message);
            })
        }
    }).catch(error => {
        const message = `L'abonnement n'a pas pu être supprimé. Réessayez dans quelques instants.`
        return generateServerErrorCode(res,500,error,message)
    })
}

export const getAbonnementByBoite = async (req: Request, res: Response) => {
    await( myDataSource.getRepository(Abonnement)
    .createQueryBuilder("a")
        .select("a") 
        .innerJoinAndSelect("a.boite", "b")
        .innerJoinAndSelect("b.modele","mo")
       // .innerJoinAndSelect("a.adressePostale","ad")
        .leftJoinAndSelect("a.redevances","redev")
        .innerJoinAndSelect("a.abonne", "ab")
        .innerJoinAndSelect("ab.categorieAbonne","ca")
        .innerJoinAndSelect("ab.activite","ac")
        .where("b.id like :key1", { key1: `%${req.params.cle}%` })
        .andWhere("a.estResilier != 1")
        .andWhere("a.deletedAt IS NULL")
        .orderBy("a.id","DESC")
        .limit(1)
        .getMany()
        )
    .then(abonnements => {
        if(abonnements === 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,abonnements,message);
    })
    .catch(error => {
        const message = `L'abonne n'a pas pu être récupéré. Réessayez dans quelques instants.`
        return generateServerErrorCode(res,500,error,message)
    })
};

export const valideAbonnement = async (req: Request, res: Response) => {
    
    await myDataSource.getRepository(Abonnement).createQueryBuilder()
    .update({ etat:"Actif" }).where("id = :Abonnement", { Abonnement: parseInt(req.params.id) })
    .execute()
    .then(abonnement => {
        const message = `L'abonnement a été validé avec success.`
        return success(res,200,abonnement,message);
    })
    .catch(error => {
        const message = `L'abonne n'a pas pu être récupéré. Réessayez dans quelques instants.`
        return generateServerErrorCode(res,500,error,message)
    })
};

export const getAbonnementBykey = async (req: Request, res: Response) => {
    await( myDataSource.getRepository(Abonnement)
    .createQueryBuilder("a")
        .select("a") 
        .leftJoinAndSelect("a.boite", "b")
        .leftJoinAndSelect("b.adressePostale", "ap")
        .leftJoinAndSelect("a.abonne", "ab")
        .leftJoinAndSelect("a.bureau", "bureau")
        .where("(a.etat != :eta AND  a.etat != :eta2 AND  a.etat != :eta3)", {eta:"En attente", eta2:"Résilié", eta3:"Inactif"})
        .andWhere("(b.refBoite like :key OR ab.nomComplet like :key OR a.refAbo like :key OR a.adresseVirtuelle like :key OR ab.telephone like :key)", { key: `%${req.params.cle}%` })
        .getMany()
        )
    .then(abonnements => {
        if(abonnements === 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,abonnements,message);
    })
    .catch(error => {
        const message = `L'abonne n'a pas pu être récupéré. Réessayez dans quelques instants.`
        return generateServerErrorCode(res,500,error,message)
    })
};

export const getAbonnementBykey2 = async (req: Request, res: Response) => {
    await( myDataSource.getRepository(Abonnement)
    .createQueryBuilder("a")
        .select("a") 
        .leftJoinAndSelect("a.boite", "b")
        .leftJoinAndSelect("b.adressePostale", "ap")
        .leftJoinAndSelect("a.remboursements","rem")
        .leftJoinAndSelect("a.abonne", "ab")
        .leftJoinAndSelect("a.bureau", "bureau")
        .where("(a.etat = :eta2)", {eta2:"Résilié"})
        .andWhere("rem.id IS NULL")
        .andWhere("(b.refBoite like :key OR ab.nomComplet like :key OR a.refAbo like :key OR a.adresseVirtuelle like :key OR ab.telephone like :key)", { key: `%${req.params.cle}%` })
        .getMany()
        )
    .then(abonnements => {
        if(abonnements === 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,abonnements,message);
    })
    .catch(error => {
        const message = `L'abonne n'a pas pu être récupéré. Réessayez dans quelques instants.`
        return generateServerErrorCode(res,500,error,message)
    })
};

export const getAbonnementBykeyAndAgence = async (req: Request, res: Response) => {
    
   var reque =  await( myDataSource.getRepository(Abonnement)
    .createQueryBuilder("a")
        .select("a") 
        .leftJoinAndSelect("a.boite", "b")
        .leftJoin("b.bureau","bureau")
        .leftJoin("a.bureau","agence")
        .leftJoin("a.agence","bur")
        .leftJoinAndSelect("a.abonne", "ab")
        .where("(a.etat != :eta AND  a.etat != :eta2 AND  a.etat != :eta3)", {eta:"En attente", eta2:"Résilié", eta3:"Inactif"})
        .andWhere("(b.refBoite like :key OR ab.nomComplet like :key OR a.refAbo like :key OR a.adresseVirtuelle like :key OR ab.telephone like :key)", { key: `%${req.params.cle}%` }));


        const donnee:boolean = await checkRole(req);
        if(donnee == false){
            if(req.body.agenceId){
                reque.andWhere("(bureau.id =:bureau OR bur.id = :bureau OR agence.id = :bureau)",{bureau: parseInt(req.body.agenceId)});
            }
        }
    await reque.getMany()
    .then(abonnements => {
        if(abonnements === 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,abonnements,message);
    })
    .catch(error => {
        const message = `L'abonne n'a pas pu être récupéré. Réessayez dans quelques instants.`
        return generateServerErrorCode(res,500,error,message)
    })
};

export const getAbonnementBykeyBureau = async (req: Request, res: Response) => {
    let reque = myDataSource.getRepository(Abonnement)
    .createQueryBuilder("a")
        .select("a") 
        .leftJoinAndSelect("a.boite", "b")
        .leftJoinAndSelect("b.bureau", "bu")
        .leftJoinAndSelect("a.abonne", "ab")
        .leftJoinAndSelect("b.adressePostale","adp")
        .where("(a.etat != :eta AND  a.etat != :eta2 AND  a.etat != :eta3)", {eta:"En attente", eta2:"Résilié", eta3:"Inactif"})
        .andWhere("(adp.adresse_postale like :key OR b.refBoite like :key OR ab.nomComplet like :key OR a.refAbo like :key OR a.adresseVirtuelle like :key OR ab.telephone like :key)", { key: `%${req.body.cle}%` });
        if(req.body.bureau){
            reque.andWhere("bu.id = :key3", { key3: parseInt(req.body.bureau) });
        }
       
    await reque.getMany().then(abonnements => {
        if(abonnements === 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,abonnements,message);
    })
    .catch(error => {
        const message = `L'abonne n'a pas pu être récupéré. Réessayez dans quelques instants.`
        return generateServerErrorCode(res,500,error,message)
    })
};
