const mongoose = require('mongoose').set('debug', false);
const Schema = mongoose.Schema;

const tools = require('../tools/general');

const shared_consts = require('../tools/shared_nodejs');

mongoose.Promise = global.Promise;
mongoose.level = 'F';

// Resolving error Unknown modifier: $pushAll
mongoose.plugin((schema) => {
  schema.options.usePushEach = true;
});

const CronMod = require('../modules/CronMod');

const CronSchema = new Schema({
  idapp: {
    type: String,
  },
  active: {
    type: Boolean,
    default: false,
  },
  descr: {
    type: String,
  },
  nomeFunzioneDbOp: {
    type: String,
  },
  startTime: {
    // Orario iniziale (es. "08:30")
    type: String,
  },
  everyXMinutes: {
    // Esegui ogni X ore
    type: Number,
  },
  quanteVolteEseguito: {
    type: Number,
    default: 0,
  },
  quanteVolteEseguiAlGG: {
    type: Number,
    default: 1,
  },
  lastJobStarted: {
    type: Date,
  },
  lastJobEnd: {
    type: Date,
  },
  log: {
    type: String,
  },
  status: {
    type: Number,
  },
  date_created: {
    type: Date,
    default: Date.now,
  },
  date_updated: {
    type: Date,
  },
});

CronSchema.statics.getFieldsForSearch = function () {
  return [{ field: 'descr', type: tools.FieldType.string }];
};

CronSchema.statics.executeQueryTable = function (idapp, params, user) {
  params.fieldsearch = this.getFieldsForSearch();
  return tools.executeQueryTable(this, idapp, params, user);
};

CronSchema.statics.startJobCron = async function (idapp) {
  // Esegui un loop su tutti i cron job che trovi per l'idapp specificato
  const Cron = this;
  try {
    const cronJobs = await Cron.find({ idapp, active: true });

    // console.log('Check startJobCron...', idapp);

    const mycronMod = new CronMod();

    const currentDate = new Date();

    for (const mycron of cronJobs) {
      const jobTime = new Date();
      const [hours, minutes] = mycron.startTime.split(':');
      jobTime.setHours(hours, minutes, 0, 0);

      // Check if jobTime has passed and if 'everyXMinutes' have elapsed since last execution
      if (!mycron.quanteVolteEseguito) mycron.quanteVolteEseguito = 0;
      const timesPerDay = mycron.quanteVolteEseguiAlGG || 1;
      const startDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate());
      let lastJobDate = null;
      if (mycron.lastJobStarted) {
        lastJobDate = new Date(
          mycron.lastJobStarted.getFullYear(),
          mycron.lastJobStarted.getMonth(),
          mycron.lastJobStarted.getDate()
        );
      }

      let tempooltre = currentDate - mycron.lastJobStarted >= mycron.everyXMinutes * 60 * 1000;
      const canExecute =
        (!mycron.lastJobStarted || // se non c'è un ultimo eseguito, esegui
          tempooltre) && // se è passato il tempo di attesa, esegui
        (mycron.lastJobStarted && (mycron.quanteVolteEseguito < timesPerDay) || // se non ho ancora raggiunto il numero di esecuzioni al giorno
          (!lastJobDate || (startDate.getTime() !== lastJobDate.getTime()))); // se non è lo stesso giorno, esegui
      if (canExecute) {
        if (currentDate >= jobTime) {
          // Execute the function at the scheduled time
          console.log(`Sto eseguendo il Cron Job: ${mycron.nomeFunzioneDbOp} alle ${currentDate.toLocaleTimeString()}`);
          const status = shared_consts.STATUS_JOB.START;
          if (!lastJobDate || startDate.getTime() !== lastJobDate.getTime()) {
            mycron.quanteVolteEseguito = 0;
          }

          const quanteVolteEseguito = mycron.quanteVolteEseguito + 1;
          await Cron.findOneAndUpdate(
            { _id: mycron._id },
            { $set: { lastJobStarted: currentDate, status, quanteVolteEseguito } },
            { new: true }
          );
          mycronMod
            .eseguiDbOp(idapp, { dbop: mycron.nomeFunzioneDbOp }, null, null)
            .then(async (ris) => {
              console.log(`${currentDate.toLocaleTimeString()} LOG JOB: ${ris.mystr}`);
              const myid = mycron._id;
              const status = shared_consts.STATUS_JOB.FINISH;
              const risupdate = await Cron.findOneAndUpdate(
                { _id: myid },
                { $set: { lastJobEnd: new Date(), status } },
                { new: true }
              );
            })
            .catch(async (err) => {
              const log = "Errore durante l'esecuzione del job: " + err.message || err;
              const status = shared_consts.STATUS_JOB.ERR;
              await Cron.findOneAndUpdate({ _id: mycron._id }, { $set: { log, status } }, { new: true });
              console.error(log);
            });
        }
      }
    }
  } catch (e) {
    console.error('Error startJobCron:', e);
    return false;
  }
};

CronSchema.statics.findAllIdApp = async function (idapp) {
  const Cron = this;

  try {
    return await Cron.find({ idapp }).then((arrrec) => {
      return arrrec;
    });
  } catch (err) {
    console.error('Errore: ', err);
  }
};

const Cron = mongoose.model('Cron', CronSchema);

Cron.createIndexes()
  .then(() => {})
  .catch((err) => {
    throw err;
  });

module.exports = { Cron };
