const db = require('../models');
const moment = require('moment');
const EmployeeModel = db.employee;
const VacationModel = db.vacation;
const VariableController = require('./variableController');
const functionController = require('./functionController');
const { Op } = require('sequelize');
const Mail = require('../functions/mail');


// MISE A JOUR CONGE
const vacationUpdateInMonth = async () => {
    const superAdmin = await db.admin.findOne({ where: { role: 'Super admin' } });
    const vacationPerMonth = await VariableController.getVacationPerMonth();        
    var employees = await EmployeeModel.findAll();
    employees.forEach(async (employee) => {
      //Prend le nombre de droit de congee par mois

      var latestVacation = await findLatestVacation(employee.id);             
      // if(employee.hiring_date) {
        // Prend le dernier congees modifiee
      if(latestVacation && latestVacation.endDate) {
        //  Nombre de jours restant apres la modification de date d'embauche
        let nbrDays = nbrDaysBetweenDates(latestVacation.endDate, moment());          
        if( latestVacation.endDate == employee.hiring_date &&  nbrDays < 28 ) {            
          latestVacation.totalVacation += await totalVacation(latestVacation.createdAt, moment());            
        }
        else {
          latestVacation.totalVacation += vacationPerMonth;            
        }
        //  Mise a jour du congee
        let r = await VacationModel.create({
          employeeId : employee.id,
          totalVacation: latestVacation.totalVacation,
          endDate: moment(),
          AdmnistratorId : superAdmin.id
        });
        
        console.log(r);
      }
      //  Si l'employée n'a encore du congé enregistrer
      else {
        var newVac = await newVacation(employee.id);
        let infoCongee = {
          employeeId : employee.id,
          totalVacation: newVac.totalVacation,
          endDate: employee.hiring_date,
          AdmnistratorId : superAdmin.id
        }
        await VacationModel.create(infoCongee);
      }
      // }
    });
};

// NOUVEAU CONGEES POUR UN EMPLOYEE
const newVacation = async (employeeId) => {
  var latestVacation = await findLatestVacation(employeeId);

  //  Si l'employee a deja un congee
  if( latestVacation ) {  
    await latestVacation.destroy();    
  }
  latestVacation = {
    totalVacation: 0
  }

  var employee = await EmployeeModel.findOne({ where: { id: employeeId }});
  //Prend le nombre de droit de congee par mois
  console.log(employee)
  if(employee && employee.hiring_date) {
    var total = await totalVacation(employee.hiring_date, moment()); 
  }
  else {
    var total = await totalVacation(moment(), moment());
  }
  latestVacation.totalVacation = total;  
  return latestVacation;  
}

const roundValue = (value) => {  

  // Vérifier si le nombre contient une virgule
  if (value.toString().indexOf('.') !== -1) {
    // Convertir le nombre en une chaîne de caractères avec deux chiffres après la virgule
    return parseFloat(value).toFixed(2);
  } else {
    // Si le nombre n'a pas de virgule, simplement retourner le nombre sans modification
    return parseInt(value);
  } 
}

//  TOTAL CONGE
const totalVacation = async ( startDate, endDate = moment() ) => {

  //Prend le nombre de droit de congee par mois
  const vacationPerMonth = await VariableController.getVacationPerMonth();  

  // Calculer combien du jours l'employee a travaille
  //  Si il n'est pas encore embaucher
  if(startDate) {
    var nbrDays = nbrDaysBetweenDates(startDate, endDate);    
  }
  else {
    nbrDays = 0;
  }
  var totalVacation = 0
  console.log(vacationPerMonth)
  //  Si moins d'un mois
  if(nbrDays < 28) {    
    totalVacation = (nbrDays * vacationPerMonth) / 28 ;
  }        
  //  Si il a travaille plus d'un mois mais leur congee n'est jamais enregistree 
  else {
    let nbrMonth = nbrDays / 28;
    totalVacation = vacationPerMonth * nbrMonth;
  }
  console.log(totalVacation)
  totalVacation = roundValue(totalVacation);
  return totalVacation;
}

//  NOMBRE DE JOURS ENTRE DEUX DATES
const nbrDaysBetweenDates = (startDate, endDate) => {
  var nbrDays = moment(endDate).diff(moment(startDate), 'days');
  return nbrDays;
}

//  TROUVER TOUTES LES CONGES


//  ENREGISTREMENT
const save = async ( vacationInformation ) => {
    try{        
        let vacationSaved = await VacationModel.create(vacationInformation);
        return vacationSaved;
    }catch(err) {
        console.log(err)
    }
};

//  TROUVER TOUTES LES CONGES
const findAll = async () => {
    return await VacationModel.findAll();
};


const findAllVacationMonth = async (employeeId, Date) => {
  
  let start = generateStartMonth(Date);
  let end = generateEndOfMonth(Date);    
  
  try {

    var vacations = await VacationModel.findAll({
      where: {     
        //  Le conge de ce mois-ci   
        [Op.and]: [          
          {createdAt: {[Op.gte]: start }}, //  >= le debut de mois
          {createdAt: {[Op.lte]: end }}, //  <= le debut de mois suivant
          { employeeId: employeeId }
        ]
      },
      order: [['createdAt','ASC']]
    });
  }
  catch(err) {
    console.log('manomboka eto' + err)    
  }
  return vacations;
}

const findVacationBeforeStart = async (employeeId, start) => {
  start = moment(start);  
  
  try {

    var vacations = await VacationModel.findOne({
      where: {     
        //  Le conge de ce mois-ci   
        [Op.and]: [          
          {createdAt: {[Op.lt]: start }}, //  < le debut de mois
          // {createdAt: {[Op.lte]: end }}, //  <= le debut de mois suivant
          { employeeId: employeeId }
        ]
      },
      order: [['createdAt','DESC']]
    });
  }
  catch(err) {
    console.log('manomboka eto' + err)    
  }
  if (!vacations) {        
    //  Congé non défini
    return {
      totalVacation : -999
    };
  }
  return vacations;  
}

const generateEndOfMonth = (date) => {
  const newDate = new Date(date);
  const nextMonth = newDate.getMonth() + 1;
  newDate.setMonth(nextMonth, 0);
  return newDate;
}

const generateStartMonth = (date) => {
  const newDate = new Date(date);  
  newDate.setDate(1);
  return newDate;
}

//  Rechercher le dernier congee
const findLatestVacation = async (employeeId) => {
    try {
      let latestVacation = await VacationModel.findOne({
        where: { employeeId: employeeId },
        order: [['createdAt', 'DESC']],
      });
      return latestVacation;
    } catch (error) {
      console.error('Error finding latest leave:', error);
      throw error;
    }
}

//  Rechercher le dernier congee
const findLatestVacationOnDate = async (employeeId, Date) => {
  startDate = generateStartMonth(Date);
  endDate = generateEndOfMonth(Date);
  try {
    let latestVacation = await VacationModel.findOne({
      //  Le conge d'un mois
      where: {
        [Op.and]: [          
          {createdAt: {[Op.gte]: startDate }}, //  >= le debut de mois
          {createdAt: {[Op.lte]: endDate }}, //  <= le debut de mois suivant
          { employeeId: employeeId }
        ],    
      },
      order: [['createdAt', 'DESC']],
    });    
    return latestVacation;
  } catch (error) {
    console.error('Error finding latest leave:', error);
    throw error;
  }
}

// RETOURNER A LA PAGE DE DEMANDE DE CONGE EN CAS D'ERREUR
const returnRequestVacation = async (errMessage, req, res) => {
  let errors = [{
    msg: errMessage
  }];  
  let employees = [];
    
  //  Trouver tout les employees
  var allEmployee = await EmployeeModel.findAll();  
  for(let i = 0; i < allEmployee.length; i++) {
    allEmployee[i].interims = [];
    if(allEmployee[i]) {
        let interims = await db.interim.findAll({ where:{ employeeId: allEmployee[i].id }});
        for(let j = 0; j < interims.length; j++) {
          let interim = await db.employee.findOne({ where: { id: interims[j].interimId}});
          if(interim) {
              allEmployee[i].interims.push(interim)
          }
        }
    }       
  }      
  
  //  Trouver leurs soldes congees
  for(let i = 0; i < allEmployee.length; i++ ) {
      let result = await findLatestVacation(allEmployee[i].id);
      
      let canApplicant = await db.adminEmployee.findOne({where : {
          [Op.and]: [
              { isApplicant: true },
              { employeeId: allEmployee[i].id },
              { AdmnistratorId: req.session.admin.id }
          ]
      }})
      
      if(result && canApplicant ) {
          let employee = allEmployee[i]           
          let fonction = await functionController.getFunctionEmployee(employee.id);
          if(fonction) {
              employee.fonction = fonction.nameFunction;
          }
          else {
              employee.fonction = '';
          }
          employee.solde = result.totalVacation
          employees.push(employee);
      }                
  }                
  res.render('pages/forms/vacation', { employees, errors, req});
}

const numberOfHolidayBetweenDates = async (start, end) => {
  let holidays = await db.holiday.findAll({
    where: {
      [Op.and]: [
        {
          date: { [Op.gte]: start }
        }, // date >= start
        {
          date: { [Op.lte]: end } // date <= end
        },
      ]
    }
  });

  return holidays.length;
}

// DEMANDE DE CONGEE
const requestVacation = async (req, res ) => {
 
  let { id, solde, start, start_hour, end, end_hour, interimId,demandeur, reason } = req.body;  

  //  VERIFIER QUE CE SONT DES FUTURES DATES
  let n = nbrDaysBetweenDates(moment(), start);

  // Date de debut plus tot qu'aujourdhui et moin d'une semaine
  //  Seul le super admin peut demander un conge avec la date de depart est moins d'une semaine  
  if( req.session && req.session.admin && req.session.admin.role !== 'Super admin') {
    if(n <= 0 ) {    
      let msg = "Date de début non valide.";
      return returnRequestVacation(msg, req, res)
    }
    if( n < 7) {
      let msg = "Date de début non valide.";
      return returnRequestVacation(msg, req, res)
    }
  }

  //  DATE LOGIQUE start <= end
  let nbrDays = nbrDaysBetweenDates(moment(start), moment(end));
  
  //  Si le start est plus tard que end
  if( nbrDays < 0 ) {
    tmp = start;
    start = end;
    end = tmp;
  }

  //  Exclus les jours fériés du solde
  n = await numberOfHolidayBetweenDates(start, end);
  nbrDays = nbrDays - n;

  
  //  VERIFIER QUE C'EST UN VRAI EMPLOYEE
  if(id !== '') {    
    let employee = await db.employee.findOne({ where: { id: id}});
    if(!employee) {      
      let msg = "Utilisateur introuvable.";
      return returnRequestVacation(msg, req, res);      
    }
    
    // heure de départ et de fin 
    let timeToDay = {
      "MT":0.5,
      "MD": 0,
      "SR": 0.5,
    }

    nbrDays += timeToDay[start_hour] + timeToDay[end_hour];    

    //  ROLE DE EMPLOYEE S'IL A UN ROLE
    let roleEmployee = await db.admin.findOne({ where: { matriculeEmployee: employee.matricule }});
    if(!roleEmployee) {      
      roleEmployee = '';      
    }

    // TROUVER LE DEMANDEUR
    let applicant = await db.admin.findOne({ where: { id: demandeur }});
    if(!applicant) {      
      let msg = "Demandeur introuvable.";
      return returnRequestVacation(msg, req, res);
    }

    //  ENREGISTRER LE CONGE OU LA DEMANDE
    let rest = roundValue(solde - nbrDays);
    let vacation = await save({
      totalVacation: rest,
      startDate: moment(start),
      startHour: start_hour,
      endDate: moment(end),
      endHour: end_hour,
      AdmnistratorId: null,
      interimId: interimId,
      reason: reason,
      applicantId: applicant.id,
      employeeId: id
    });
    
  
    //  ENVOYER LE MAIL VERS LEUR SUPERIEUR DE L'EMPLOYEE
    //  Fonction de l'employee
    let fonction = await functionController.getFunctionEmployee(employee.id);    
    employee.fonction = fonction ? fonction.nameFunction : '';    

    const MAIL = process.env.ENV == 'prod' ? process.env.MAIL : process.env.MAIL_LOCAL;

    //  Validateurs à envoyer le mail de notifications
    let idValidators = await db.adminEmployee.findAll({ where: {
      [Op.and]: [
        { isValidator: true },
        { employeeId: employee.id }
      ]
    }});

    let allAdmin = [];
    for(let i = 0; i < idValidators.length; i++) {
      let admin = await db.admin.findOne({ where:{ id: idValidators[i].AdmnistratorId}});
      if(admin) {
        allAdmin.push(admin);
      }
    }    
    var mails = [];
    allAdmin.forEach(function(admin) {
      mails.push(admin.email);
    })    
    
    let emailsToSend = [];
    for(let i = 0; i < mails.length; i++ ) {
      let email = mails[i];      
      if( email !== applicant.email ) {
        let mailDetail = {};                    
        mailDetail.recipient = email;
        mailDetail.subject = 'Demande de validation de congé';
        mailDetail.message = `Bonjour, 
${employee.name_employee} ${employee.last_name_employee}
matricule:${employee.matricule}
Fonction: ${employee.fonction}
Veuillez-vous connecter sur le site ${process.env.SITE}`
        emailsToSend.push(mailDetail);
      };                
    }
    
    //  ATTEND 24H AVANT D'ENVOYER LES MAILS
    setTimeout(async () => {
      let exist = await db.vacation.findByPk(vacation.id);
      if(exist) {        
        Mail.sendAllMails(emailsToSend);
      }
    }, 1000 * 60 * 60 * 24);


    if(req.body.interimaire !== '') {

      let data = {
        poste: employee.fonction,
        direction: req.body.direction,
        holder: employee.name_employee + ' ' + employee.last_name_employee,
        interim: req.body.interimaire,
        vacationId: vacation.id,
        permissionId: null,
      }
  
      // Passation de service
      try {
          var passFile = await db.passingFile.create(data);
      }
      catch(err) {
          console.log(err);
          return res.send(err);
      }
  
      //  Tache
      let task = req.body.taches;
      let deliverable = req.body.livrables;
      let reference = req.body.referentiels;
  
      if(task && deliverable && reference) {            
          if( Array.isArray(task) && Array.isArray(deliverable) && Array.isArray(reference) ) {
              for(let i = 0; i < task.length && i < deliverable.length && i < reference.length; i++) {                    
                  if(task[i] && deliverable[i] && reference[i]) {
                      let rslt = await db.task.create({
                          description : task[i], 
                          deliverable : deliverable[i],
                          reference : reference[i],
                          passingFileId: passFile.id                
                      });
                  }
              }
          }
          else {                
              let rslt = await db.task.create({
                  description : task, 
                  deliverable, 
                  reference,
                  passingFileId: passFile.id
              });                
          }
      }
  
      //  Personnel
      let noms = req.body.noms;
      let fonctions = req.body.fonctions;
  
      if(noms && fonctions) {            
          if( Array.isArray(noms) && Array.isArray(fonctions) ) {
              for(let i = 0; i < noms.length && i < fonctions.length ; i++) {
                  if(noms[i] && fonctions[i]) {
                      let rslt = await db.personnel.create({
                          name_and_last: noms[i],
                          fonction: fonctions[i],
                          passingFileId: passFile.id                
                      });
                  }
              }
          }
          else {                
              let rslt = await db.personnel.create({
                  name_and_last: noms,
                  fonction: fonctions,
                  passingFileId: passFile.id
              });                
          }
      }
  
      //  Materiels
      let description = req.body.descriptions;
      let quantity = req.body.quantities;
      let state = req.body.etats;      
  
      if(description && quantity && state) {            
          if( Array.isArray(description) && Array.isArray(quantity) && Array.isArray(state)) {
              for(let i = 0; i < description.length && i < quantity.length && i < state.length; i++) {
                  if(description[i] && quantity[i] && state[i]) {
                      let rslt = await db.material.create({
                          description: description[i],
                          quantity: quantity[i],
                          state: state[i],
                          passingFileId: passFile.id                
                      });
                  }
              }
          }
          else {                
              let rslt = await db.material.create({
                  description: description,
                  quantity: quantity,
                  state: state,
                  passingFileId: passFile.id
              });                
          }
      }
  
      // Signatures
      let doc_type = req.body.typeDocs;
      let responsability_level = req.body.responsabilites;
  
      if(doc_type && responsability_level) {            
          if( Array.isArray(doc_type) && Array.isArray(responsability_level) ) {
              for(let i = 0; i < doc_type.length && i < responsability_level.length ; i++) {
                  if(doc_type[i] && responsability_level[i]) {
                      let rslt = await db.signature.create({
                          doc_type: doc_type[i],
                          responsability_level: responsability_level[i],
                          passingFileId: passFile.id                
                      });
                  }
              }
          }
          else {                
              let rslt = await db.signature.create({
                  doc_type: doc_type,
                  responsability_level: responsability_level,
                  passingFileId: passFile.id                                    
              });                
          }
      }    
    }
    return res.redirect(`/`);
  }
  else {
    errors = [{
      msg: "Veuillez choisir un employé"
    }];
    //  Trouver tout les employees
    let results = await EmployeeModel.findAll();

    //  Trouver leurs soldes congees
    let employees = [];
    for(let i = 0; i < results.length; i++ ) {
        let result = await findLatestVacation(results[i].id);
        if(result) {              
            let employee = results[i];
            employee.solde = result.totalVacation              
            employees.push(employee);
        }
    }
    res.render('pages/forms/vacation', { employees ,errors, req});    
  }  
}

// MISE A JOUR ET VALIDATION DE CONGEE
const updateVacation = async (req, res ) => {  

  let { idEmployee, valid, validator } = req.body;
  console.log(idEmployee);

  if(idEmployee !== '' && req.params.id !== '' ) {                

    //  Il y a une validation d'un conge n'est pas encore validee    
    if(validator && valid == 'on' ) {      
      let admin = await db.admin.findOne({ where: { id: validator }})
      if(admin) {        
        //  Le congé est valider        
        let vacation = await VacationModel.update(
          { AdmnistratorId: (valid == 'on') ? admin.id : null },
          { where: {id: req.params.id }}
        );
        
        //  Envoyer mail vers demandeur que le conge est valider
        //  Trouver le demandeur et l'employee  
        vacation = await VacationModel.findOne({ where: { id: req.params.id }});        
        let applicant = await db.admin.findOne({ where: {id : vacation.applicantId }});
        let employee = await db.employee.findOne({ where: { id: vacation.employeeId }})
        if(applicant) {
          let email = applicant.email;
          const MAIL = process.env.ENV == 'prod' ? process.env.MAIL : process.env.MAIL_LOCAL;
          
          //  Trouver le validateur
          let validateur = await db.admin.findOne({ where: { id: vacation.AdmnistratorId }});
          if(validateur) {      
            let mail = {};
            mail.recipient = email;
            mail.subject = 'Validation de congé';
            mail.message = 
            `Bonjour, 
${employee.name_employee} ${employee.last_name_employee}
matricule:${employee.matricule}
congé validé par ${validateur.firstName} ${validateur.lastName}
Veuillez-vous connecter sur le site ${process.env.SITE} pour voir le détail`;
            Mail.sendEmail(mail);                
          }
        }
      }      
      return res.redirect('/');
    } 
  }
  else {
    errors = [{
      msg: "Veuillez choisir un employé"
    }];
    //  Trouver tout les employees
    let results = await EmployeeModel.findAll();

    //  Trouver leurs soldes congees
    let employees = [];
    for(let i = 0; i < results.length; i++ ) {
        let result = await findLatestVacation(results[i].id);
        if(result) {
            let employee = {
                employee: results[i],
                solde: result.totalVacation
            }
            employees.push(employee);
        }
    }
    res.render('pages/forms/vacation', { employees ,errors, req});    
  }    
  res.redirect(`/`);
}


//  Conge en cours
const currentVacationAndEmployee = async ( nowDate ) => {
  let now = nowDate;
  //  Congee en cours
  let currents = await VacationModel.findAll({
    where : {
      [Op.and]: [
        { startDate: { [Op.lte]: now }}, // startDate <= now
        { startDate: { [Op.not]: null }}, // startDate is not null
        { endDate: { [Op.gte]: now }}, // endDate >= now
        { AdmnistratorId: { [Op.not]: null }},
        { AdmnistratorId: { [Op.gt]: 0 }},
      ]      
    }
  });
  var data = []
  if(currents.length > 0) {    
    //  Trouver l'employe en congee
    for(let i = 0; i < currents.length; i++ ) {      
      let employee = await EmployeeModel.findOne({ where: { id: currents[i].employeeId }});
      //  Leur fonction      
      if(employee) {        
        var employeeFunct = await db.employeeFunction.findOne({
          where: { employeeId: employee.id },
          order: [['date', 'DESC']]
        });
        if (employeeFunct) {
            let fonction = await db.function.findOne({
                where: { id: employeeFunct.functionId }
            });
            if(fonction)
            employee.fonction = fonction;          
        }
        employee.vacation = currents[i];
        //  Trouver le validateur
        let validateur = await db.admin.findOne({ where: { id: employee.vacation.AdmnistratorId }});
        if(validateur) {                    
          employee.vacation.validateur = validateur;
        }        

        employee.restDay = nbrDaysBetweenDates(now, employee.vacation.endDate);        
        data.push(employee);        
      }      
    }
  }  
  return data;
}


// conge prochain
const nextVacationAndEmployee = async ( req, nowDate ) => {
  let now = nowDate;
  let vacations = await VacationModel.findAll({
    where: {
      [Op.and]: [
        { startDate: { [Op.not]: null }}, // startDate is not null       
        { startDate: { [Op.gt]: now }}, //  startDate > now
        { AdmnistratorId: { [Op.not]: null }},
        { AdmnistratorId: { [Op.gt]: 0 }}, // Valeur > 0
      ]
    }
  });
  
  let data = [];
  for( let i = 0; i < vacations.length; i++) {
    let nbrDays = nbrDaysBetweenDates( now, vacations[i].startDate );        
    console.log(nbrDays)
    if(nbrDays <= 30) {
      
      let employee = await EmployeeModel.findOne({ where: { id: vacations[i].employeeId }});
      //  Leur fonction
      if(employee) {        
        employee.fonction = await functionController.getFunctionEmployee(employee.id);
        employee.vacation = vacations[i];
        //  Trouver le validateur
        if(employee.vacation) {
          var validateur = await db.admin.findOne({ where: { id: employee.vacation.AdmnistratorId }});
          if(validateur) {                    
            employee.vacation.validateur = validateur;
          }        
        }        
        console.log(vacations[i].startDate);
        employee.nbrDaysBefor = nbrDaysBetweenDates(now, vacations[i].startDate);
        let canApplicant = await db.adminEmployee.findOne({where: {
          [Op.and]: [
            { isApplicant: true },
            { employeeId: employee.id },
            { AdmnistratorId: req.session.admin.id }
          ]
        }});
        if(canApplicant) {
          data.push(employee);
        }
      }            
    }
  };  
  return data;
}

//  Conge en alerte
const alertVacationAndEmployee = async ( req, nowDate ) => {
  let now = nowDate;
  let data = [];
  let allEmployees = await EmployeeModel.findAll();

  let employees = [];
  for(let i = 0; i < allEmployees.length; i++) {
    let employee = await db.employee.findOne({ where: { id : allEmployees[i].id }});
    let canApplicant = await db.adminEmployee.findOne({where: {
      [Op.and]: [
        { isApplicant: true },
        { employeeId: employee.id },
        { AdmnistratorId: req.session.admin.id }
      ]
    }});
    if(employee && canApplicant ) {
      employees.push(employee);
    }
  }

  for(let i = 0; i < employees.length; i++) {
    let last = await findLatestVacation(employees[i].id);
    if(last) {
      //  Si superieur ou egale a 20 jours
      if( last.totalVacation >= 20 ) {
        employees[i].vacation = last;
        //  Trouver leur fonction
        employees[i].fonction = await functionController.getFunctionEmployee(employees[i].id);      
        data.push(employees[i]);
      }
    }
  }  
  return data;
};

//  Conge en attente
const waitingVacAndEmployee = async (req) => {

  let vacations = await VacationModel.findAll({
    where: { AdmnistratorId: null }
  });
  
  let data = [];
  for(let i = 0; i < vacations.length; i++) {      
    let employee = await EmployeeModel.findOne({ where: { id: vacations[i].employeeId }});
    let canValidate = await db.adminEmployee.findOne({ where: {
      [Op.and]: [
        { isValidator: true },
        { employeeId: employee.id },
        { AdmnistratorId: req.session.admin.id }
      ]
    }});    
    //  Leur fonction
    if(employee && canValidate) {
      var prevVacation = await VacationModel.findAll({
        where: { employeeId: employee.id },
        order: [['createdAt', 'DESC']],
        limit: 2        
      });            
      employee.fonction = await functionController.getFunctionEmployee(employee.id);
      employee.vacation = vacations[i];
      //  Trouver le demandeur
      let applicant = await db.admin.findOne({ where: { id: employee.vacation.applicantId }});
      if(applicant) {
        employee.vacation.applicant = applicant;
      }
      employee.prevVacation = prevVacation[1]; // Prend l'avant dernier
      data.push(employee);
    }            
  }
  return data;
}


const reject = async (req, res) => {
  const ID_SUPER_ADMIN = 2;
  const REJECT_SYMBOLE = -1;
  let idVacation = parseInt(req.body.idVacation);
  let rejectReason = req.body.reject;

  let vacation = await VacationModel.findOne({ where: { id: idVacation } });
  if (!vacation) {
    return res.redirect('/');
  }
  let nbrDays = nbrDaysBetweenDates(vacation.startDate, vacation.endDate);

  //  Exclure le jour férié
  let n = await numberOfHolidayBetweenDates(vacation.startDate, vacation.endDate);
  nbrDays = nbrDays - n;

  // heure de départ et de fin 
  let timeToDay = {
    "MT":0.5,
    "MD": 0,
    "SR": 0.5,
  }

  nbrDays += timeToDay[vacation.startHour] + timeToDay[vacation.endHour]; 


  //  Envoyer l'email au demandeur que le conge est rejeter
  //  Trouver le demandeur et l'employee  
  if(vacation) {

    let applicant = await db.admin.findOne({ where: {id : vacation.applicantId }});
    let employee = await db.employee.findOne({ where: { id: vacation.employeeId }})
    if(applicant) {
      let email = applicant.email;      
      
      //  Trouver le rejecteur
      let rejector = await db.admin.findOne({ where: { id: req.session.admin.id }});
      if(rejector) {                    
        employee.rejector = rejector;
        let mail = {};
        mail.recipient = email;          
        mail.subject = 'Demande de congé';
        mail.message = `${employee.name_employee} ${employee.last_name_employee}
matricule:${employee.matricule}
congé rejeté par ${rejector.firstName} ${rejector.lastName}.`;        

        Mail.sendEmail(mail);            
      }
    }
  }

  try {
    let rejected = await db.vacationRejected.create({ 
        employeeId: vacation.employeeId,   
        startDate: vacation.startDate,
        endDate: vacation.endDate,           
        rejectReason: rejectReason,
        rejectedBy: req.session.admin.id
    });

    setTimeout(async () => await rejected.destroy(), 1 * 1000 * 60 * 60 * 24);

    let last = await findLatestVacation(vacation.employeeId);
    if (!last) {
      return res.redirect('/');
    }
    let newTotal = nbrDays + last.totalVacation;
    await VacationModel.create({
      employeeId: vacation.employeeId,
      totalVacation: newTotal,
      startDate: null,
      startHour: null,
      endDate: new Date(),
      endHour: null,
      AdmnistratorId: ID_SUPER_ADMIN,
    });

    await vacation.update({
      AdmnistratorId: REJECT_SYMBOLE,
    })
    // await vacation.destroy();    
    res.redirect('/')
  }
  catch(err) {
    console.log(err);
    res.redirect('/');
  }

};

const rejectedVacAndEmployee = async ( nowDate ) => {
  let now = new Date();
  let rejectedVacs = await db.vacationRejected.findAll({
    where: {              
         rejectedBy : {[Op.not]: null }
    }
  });
  let data = [];
  for(let i = 0; i < rejectedVacs.length; i++) {
    let nbrDays = nbrDaysBetweenDates( rejectedVacs[i].createdAt, now );       
    if(nbrDays < 1) {
      
      let employee = await EmployeeModel.findOne({ where: { id: rejectedVacs[i].employeeId }});
      //  Leur fonction
      if(employee) {        
        employee.fonction = await functionController.getFunctionEmployee(employee.id);      
        employee.rejectedVac = rejectedVacs[i];  
        //  Trouver le rejecteur
        let rejector = await db.admin.findOne({ where: { id: rejectedVacs[i].rejectedBy }});
        if(rejector) {                    
          employee.rejector = rejector;
        }                
        data.push(employee);
      }            
    }
    else {
      await rejectedVacs[i].destroy();
    }
  };  
  return data;
}

const dateDepartVacation = async () => {
  let now = new Date();

  let mailNotSend = ["shayan@technopet.mg"];
  //  Jour de depart de conge validee
  let nowVacations = await db.vacation.findAll({
    where: {
      [Op.and]: [
        { startDate: now },
        { AdmnistratorId: { [Op.not]: null }}
      ]
    }
  });

  if(nowVacations.length > 0 ) {
    for(let j = 0; j < nowVacations.length; j++) {
      const vacation = nowVacations[j];
      let employee = await db.employee.findOne(
        { where: { id: vacation.employeeId }}
      );
      if(employee) {
      //  Validateurs à envoyer le mail de notifications
      let idValidators = await db.adminEmployee.findAll({ where: {
        [Op.and]: [
          { isValidator: true },
          { employeeId: employee.id }
        ]
      }});

      let interims = await db.interim.findAll({
        where: { employeeId: employee.id }
      })
      let chInterims = '';
      if(interims.length > 0) {
        interims.forEach(async (interim) => {
          let interimEmp = await db.employee.findOne({where: { id: interim.interimId }});
          if(chInterims !== '') {                
            chInterims += ' ou au ' + interimEmp.name_employee + ' ' + interimEmp.last_name_employee;
          }
          else if(interimEmp) {              
            chInterims += 'au ' + interimEmp.name_employee + ' ' + interimEmp.last_name_employee;
          }
        });
      }                      

      vacation.startDate += vacation.startHour ?? '';
      vacation.endDate += vacation.endHour ?? '';

        if(idValidators.length > 0) {
          let emailsToSend = [];          

          for(let i = 0; i < idValidators.length; i++) {              
            const idAdmin = idValidators[i];
            let admin = await db.admin.findOne({ where:{ id: idAdmin.AdmnistratorId }});
            if(admin && admin.email) {
              if(!mailNotSend.some(mail => mail == admin.email)) {
                let email = {};
                email.recipient = admin.email;
                email.subject = 'DEPART EN CONGE';
                email.message = 
                `Bonjour,
                  
  Je suis, ${employee.name_employee} ${employee.last_name_employee}, en congé du ${vacation.startDate} au ${vacation.endDate} ${halfDay} inclus.

  Comme je n'aurais pas accès à ma messagerie, je prendrai connaissance de votre message à mon retour.
  Merci de contacter ${chInterims}.
  Cordialement,`;
                }

                emailsToSend.push(email);                                                  
            };
          }
        }
        Mail.sendAllMails(emailsToSend);
      }
    }  
  }
}

const historicVacAndEmployee = async (req) => {
  const nowDate = moment();
  let vacations = await VacationModel.findAll({
    where: { 
      startDate: {[Op.not]: null},
      endDate: {[Op.lt]: nowDate }
    }
  });
  
  let data = [];  
  for(let i = 0; i < vacations.length; i++) {      
    var employee;    
    employee = await EmployeeModel.findOne({ where: { id: vacations[i].employeeId }});      

    let canApplicant = await db.adminEmployee.findOne({ where: {
      [Op.and]: [
        { isApplicant: true },
        { employeeId: employee.id },
        { AdmnistratorId: req.session.admin.id }
      ]
    }});    
    //  Leur fonction
    if(employee && canApplicant) {      
      employee.fonction = await functionController.getFunctionEmployee(employee.id);
      employee.vacation = vacations[i];
      //  Trouver le demandeur
      let applicant = await db.admin.findOne({ where: { id: employee.vacation.applicantId }});
      if(applicant) {
        employee.vacation.applicant = applicant;
      }
      
      data.push(employee);
    }            
  }      
  return data;
}

const recallByMail = async () => {
  let vacations = await VacationModel.findAll({
    where: { AdmnistratorId: null }
  });
    
  for(let i = 0; i < vacations.length; i++) {      
    let employee = await EmployeeModel.findOne({ where: { id: vacations[i].employeeId }});                  
    employee.fonction = await functionController.getFunctionEmployee(employee.id);
    employee.vacation = vacations[i];           
    
    //  Validateurs à envoyer le mail de notifications
    let idValidators = await db.adminEmployee.findAll({ where: {
      [Op.and]: [
        { isValidator: true },
        { employeeId: employee.id }
      ]
    }});
    
    let allAdmin = [];
    for(let i = 0; i < idValidators.length; i++) {
      let admin = await db.admin.findOne({ where:{ id: idValidators[i].AdmnistratorId}});
      if(admin) {
        allAdmin.push(admin);
      }
    }    

    let applicant = await db.admin.findByPk(vacations[i].applicantId);
    var mails = [];
    allAdmin.forEach(function(admin) {
      mails.push(admin.email);
    })          
    
    let emailsToSend = [];
    for(let i = 0; i < mails.length; i++ ) {
      let email = mails[i];      
      if( applicant && email !== applicant.email ) {
        let mail = {};
        mail.recipient = email;
        mail.subject = 'Demande de validation de congé';
        mail.message = `${employee.name_employee} ${employee.last_name_employee}
matricule:${employee.matricule}
Fonction: ${employee.fonction}
Veuillez-vous connecter sur le site ${process.env.SITE}`;
        emailsToSend.push(mail);
      };              
    }    
    Mail.sendAllMails(emailsToSend);
  }
}           

const sendMailAllAlert = async () => {
    let allEmployees = await EmployeeModel.findAll();
    let emailsToSend = [];
    for(let i = 0; i < allEmployees.length; i++) {
        let mail = {};
        let last = await findLatestVacation(allEmployees[i].id);    
        //  Si superieur ou egale a 20 jours
        if( last && last.totalVacation >= 20 ) {
          allEmployees[i].vacation = last;
          //  Trouver leur fonction
          allEmployees[i].fonction = await functionController.getFunctionEmployee(allEmployees[i].id); 
        
          //  Chercher l'adresse a envoyer l'email pour l'alerter
          let selfAdmin = await db.admin.findOne({ where:{ matriculeEmployee: allEmployees[i].matricule } });
          let email;
          if(selfAdmin) {
              email = selfAdmin.email;
          }else if( allEmployees[i].AdmnistratorId ) {
              let leader  = await db.admin.findOne({ where:{ id: allEmployees[i].AdmnistratorId }});
              if(leader) {
              email = leader.email;
              }
          }      
          //  Envoyer le mail
          if(email) {
              mail.recipient = email;
              mail.subject = 'Congé en alerte';
              mail.message = `Mme/Mr ${allEmployees[i].name_employee} ${allEmployees[i].last_name_employee}
      Matricule:${allEmployees[i].matricule}
      Solde de congé en alerte: ${last.totalVacation} jours.Vous devez le regler à inférieur à 20 jours, avant la fin du mois.
      Veuillez-vous connecter sur le site ${process.env.SITE}`;              
              emailsToSend.push(mail);     
          }        
        }
    }
    Mail.sendMailAt8hours(emailsToSend);
}

const saveOnePlanning = async (req, res) => {
  let { idEmployee, start, start_hour, end, end_hour } = req.body;

   //  VERIFIER QUE CE SONT DES FUTURES DATES
  let n = nbrDaysBetweenDates(moment(), start);

  // Date de debut plus tot qu'aujourdhui et moin d'une semaine
  //  Seul le super admin peut placer un planning passé
  if( req.session && req.session.admin && req.session.admin.role !== 'Super admin') {
    if(n <= 0 ) {          
      return res.redirect('/planning');
    }    
  }

  //  DATE LOGIQUE start <= end
  let nbrDays = nbrDaysBetweenDates(moment(start), moment(end));
  
  //  Si le start est plus tard que end
  if( nbrDays < 0 ) {
    tmp = start;
    start = end;
    end = tmp;
  }

  // verifier l'employee
  let employee = await db.employee.findByPk(idEmployee );
  if(!employee) {
    return res.redirect('/planning');
  }

  let planning = await db.planning.create({
    employeeId: employee.id,
    startDate: start,
    startHour: start_hour,
    endDate: end,
    endHour: end_hour,
    applicantId: req.session.admin.id,
  });

  return res.redirect('/planning');
}

const findFuturePlanning = async (req) => {
  const nowDate = moment();
  let plannings = await db.planning.findAll({
    where: { 
      startDate: {[Op.gte]: nowDate},
      endDate: {[Op.gte]: nowDate }
    }
  });
  
  let data = [];  
  for (let i = 0; i < plannings.length; i++) {
    let employee = await EmployeeModel.findOne({ where: { id: plannings[i].employeeId }});
    let canApplicant = await db.adminEmployee.findOne({ where: {
      [Op.and]: [
        { isApplicant : true },
        { employeeId: employee.id },
        { AdmnistratorId: req.session.admin.id }
      ]
    }});    
    //  Leur fonction
    if(employee && canApplicant) {      
      employee.fonction = await functionController.getFunctionEmployee(employee.id);
      employee.planning = plannings[i];

      //  Trouver le demandeur
      let applicant = await db.admin.findOne({ where: { id: employee.planning.applicantId }});
      if(applicant) {
        employee.planning.applicant = applicant;
      }
      
      data.push(employee);
    }            
  }
  return data;
}

const editOnePlanning = async (req, res) => {
  const ID = req.params.id;

  let planning = await db.planning.findByPk(ID);
  if(!planning) {
    return res.redirect('/planning');
  }

  let { start, start_hour, end, end_hour } = req.body;

  //  DATE LOGIQUE start <= end
  let nbrDays = nbrDaysBetweenDates(moment(start), moment(end));
  
  //  Si le start est plus tard que end
  if( nbrDays < 0 ) {
    tmp = start;
    start = end;
    end = tmp;
  }

  await planning.update({
    startDate: start,
    startHour: start_hour,
    endDate: end,
    endHour: end_hour
  });

  return res.redirect('/planning');

}

const historiquePerso = async (req, res) => {
  const ID = req.params.idEmployee;

  //  Verification id
  const employee = await db.employee.findByPk(ID);
  console.log(ID);
  if (!employee) {
    return res.redirect('/employee/');
    // return ID
  }

  let vacations = await db.vacation.findAll({
    where: {
      employeeId: ID
    },
    order: [['createdAt', 'DESC']]
  });

  return res.render('pages/liste/historique.vacation.ejs', { employee, vacations, req});
  // return vacations;
}

module.exports = {
  vacationUpdateInMonth,
  findAll,
  nbrDaysBetweenDates,
  save,
  newVacation,
  findLatestVacation,
  totalVacation,
  requestVacation,
  updateVacation,
  currentVacationAndEmployee,
  nextVacationAndEmployee,
  alertVacationAndEmployee,
  waitingVacAndEmployee,
  roundValue,
  reject,
  rejectedVacAndEmployee,    
  findAllVacationMonth,
  dateDepartVacation,
  historicVacAndEmployee,
  recallByMail,
  sendMailAllAlert,
  findLatestVacationOnDate,
  saveOnePlanning,
  findFuturePlanning,
  editOnePlanning,
  findVacationBeforeStart,
  generateEndOfMonth,
  generateStartMonth,
  historiquePerso
}


