const express = require('express');
const router = express.Router();
const mongoose = require('mongoose').set('debug', false);
const { CfgServer } = require('../models/cfgserver');

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

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

const fs = require('fs');

const { City } = require('../models/city');
const Product = require('../models/product');
const Inventariogm = require('../models/inventariogm');
const Importamacro = require('../models/importamacro');
const ProductInfo = require('../models/productInfo');
const CatProd = require('../models/catprod');
const Author = require('../models/author');
const Publisher = require('../models/publisher');
const SubCatProd = require('../models/subcatprod');
const Gasordine = require('../models/gasordine');

const { User } = require('../models/user');

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

const { ImageDownloader } = require('../tools/general.js');

const path = require('path');

var { authenticate } = require('../middleware/authenticate');

router.post('/updateval', authenticate, async (req, res) => {
  console.log('/updateval', req.body.pairval);
  idapp = req.body.idapp;
  pair = req.body.pairval;

  return await CfgServer.findOneAndUpdate(
    { chiave: pair.chiave, idapp, userId: pair.userId }, { $set: pair },
    { new: false }).then((item) => {
      // CfgServer.find({ chiave: pair.chiave }, (err, item) => {
      if (!!item) {
        res.status(200).send();
      } else {
        res.status(400).send();
      }
    }).catch(err => {
      console.log('ERR:', err);
      res.status(400).send();
    });

});

function fixURL(url) {
  return url.replace(/https:\//g, 'https://');
}

async function downloadImgIfMissing(productInfo) {

  if (!productInfo.image_link)
    return { prodInfo: null, aggiornatoimg: false };

  const img = 'upload/products/' + productInfo.image_link.split('/').pop();
  const savePath = path.resolve(__dirname, img); // Sostituisci con il percorso dove salvare l'immagine

  if (!productInfo.imagefile || !fs.existsSync(savePath)) {
    // Download image from the URL productInfo.image_link
    productInfo.imagefile = img;

    const downloader = new ImageDownloader();

    const aggiornatoimg = await downloader.downloadImage(productInfo.image_link, savePath).then(result => {
      if (result) {
        // console.log('Download completato con successo!');
      } else {
        console.log('Download non riuscito.');
      }

      return result;

    });
    return { prodInfo: productInfo, aggiornatoimg };
  }

  return { prodInfo: null, aggiornatoimg: false };
}

async function completaSettaggioProduct_AndProductInfo(arrcampi_productInfo, arrcampi_product, rec, product, productInfo) {

  try {
    if (shared_consts.CAMPI_PRODUCTINFO_CONVERT.includes('weight_and_unit')) {
      if (rec.hasOwnProperty('weight_and_unit')) {
        const ris1 = tools.getWeightAndUnitByText(rec['weight_and_unit']);
        if (ris1) {
          productInfo.weight = ris1.weight;
          productInfo.unit = ris1.unit;
        }
      }

    }

    if (shared_consts.CAMPI_PRODUCTINFO_CONVERT.includes('weight_and_unit_lordo')) {
      if (rec.hasOwnProperty('weight_and_unit_lordo')) {
        const ris2 = tools.getWeightAndUnitByText(rec['weight_and_unit_lordo']);
        if (ris2) {
          productInfo.weight_lordo = ris2.weight;
          productInfo.unit_lordo = ris2.unit;
        }
      }
    }

    if (rec.hasOwnProperty('link_scheda')) {
      if (fixURL(rec['link_scheda']))
        productInfo['link_scheda'] = fixURL(rec['link_scheda'])
    }

    for (const campo of shared_consts.PRODUCTINFO.CAMPI_FIRST_UPPERCASE) {

      if (rec.hasOwnProperty(campo)) {
        let mystr = tools.capitalize(rec[campo]).trim();
        if (mystr)
          productInfo[campo] = mystr;
      }
    }

    // Conversione in Euro
    for (campoprezzo of shared_consts.CAMPI_EURO) {
      if (rec.hasOwnProperty(campoprezzo)) {
        product[campoprezzo] = tools.convertPriceEurToValue(rec[campoprezzo])
      }
    }

    if (!rec.hasOwnProperty('img') && product.code) {
      productInfo.imagefile = 'upload/products/' + product.code + '.jpg';
    } else {
      if (rec.hasOwnProperty('img')) {
        if (rec['img']) {
          productInfo.imagefile = 'upload/products/' + rec['img'];
        } else {
          productInfo.imagefile = '';
        }
      }
    }

    if (rec.hasOwnProperty('old_code')) {
      const old_code = rec['old_code'];
      let oldrec = await ProductInfo.findOne({ code: old_code }).lean();
      if (oldrec) {
        const precid = productInfo._id;
        const preccode = productInfo.code;

        productInfo = oldrec;
        if (precid)
          productInfo._id = precid;
        else
          delete productInfo._id;

        productInfo.code = preccode;
      }
    }
    if (rec.hasOwnProperty('productTypes')) {
      productInfo.productTypes = productInfo.productTypes;
    } else {
      productInfo.productTypes = [shared_consts.PRODUCTTYPE.PRODUCT];
    }

    return { product, productInfo };

  } catch (e) {
    console.error('Err', e);
  }


  return { product, productInfo };
}

function getValoriAndIndice(dati, arrinclude) {
  const campi = dati;

  for (const key in campi) {
    if (Object.hasOwnProperty.call(obj, key)) {
      const value = obj[key];
      console.log(`${key}: ${value}`);
    }
  }

  const risultato = campi.map((campo, indice) => {
    let mycampo = campo.trim();
    if (arrinclude) {
      if (arrinclude.includes(mycampo))
        return { name: mycampo, ind: indice };
    } else {
      return { name: mycampo, ind: indice };
    }

  });

  return risultato;
}

function getValoriAndIndice_ProductInfo(dati) {
  //return getValoriAndIndice(dati, shared_consts.CAMPI_PRODUCTINFO)
  return shared_consts.CAMPI_PRODUCTINFO;
}

function getValoriAndIndice_Product(dati) {
  //return getValoriAndIndice(dati, shared_consts.CAMPI_PRODUCT);
  return shared_consts.CAMPI_PRODUCT;
}

async function extractArrayDataFromCSV(idapp, rec) {

  try {
    // la prima riga contiene il nome della proprietà:
    let productInfo = {
      idapp: idapp,
      idCatProds: [],
      idSubCatProds: [],
    };

    let product = {
      idapp,
    };

    arrcampi_productInfo = getValoriAndIndice_ProductInfo(null);
    arrcampi_product = getValoriAndIndice_Product(null);

    for (const campoobj of arrcampi_productInfo) {
      if (rec.hasOwnProperty(campoobj.name)) {
        let myval = tools.ripulisciCampo(rec[campoobj.name]);
        productInfo[campoobj.name] = (myval === 'TRUE' || myval.toUpperCase() === 'SI') ? true : ((myval === 'FALSE' || myval.toUpperCase() === 'NO') ? false : myval);
      }

    }

    for (const campoobj of arrcampi_product) {
      if (rec.hasOwnProperty(campoobj))
        product[campoobj] = rec[campoobj];
    }

    const ris = await completaSettaggioProduct_AndProductInfo(arrcampi_productInfo, arrcampi_product, rec, product, productInfo);

    /*
      // code: product.code,
      name: product.name,
      link: product.link,
      idCatProds: [],
      idSubCatProds: [],
      img: 'upload/products/' + product.code + '.jpg',
      weight: product.weight,
      unit: tools.getIdUnitsByText(product.unit),
    }
  
  
    */

    return ris;


  } catch (e) {
    console.error('Err', e);
  }

  return dataObjects;

};

function extractNameAndSurnameByComplete(name_complete) {

  if (name_complete) {
    const name = name_complete.split(' ')[0];
    const surname = name_complete.split(' ')[1];
    return { name, surname };
  } else {
    return { name: '', surname: '' };
  }
}

router.post('/import', authenticate, async (req, res) => {

  try {
    const cmd = req.body.cmd;
    const idapp = req.body.idapp;
    const data = req.body.data;
    const options = req.body.data.options;

    const liste = require('../data/liste');
    let dataObjects = null;

    if (cmd === shared_consts.Cmd.CITIES_SERVER) {
      return await City.insertMany(liste.Comuni).then((ris) => {
        return res.status(200).send(true);
      });
    } else if (cmd === shared_consts.Cmd.INVENTARIO) {
      dataObjects = JSON.parse(`[${data.arrdata}]`);
      let updated = 0;
      let imported = 0;
      let errors = 0;

      for (const recinv of dataObjects) {
        let isnuovo = false
        let setta = false

        let inventario = recinv;

        inventario.idapp = idapp;

        let risrec = await Inventariogm.findOneAndUpdate(queryprod, { $set: inventario }, { new: true, upsert: true });
      }

    } else if (cmd === shared_consts.Cmd.MACRO_CATALOGO_JSON) {
      let updated = 0;
      let imported = 0;
      let errors = 0;

      dataObjects = null;

      try {
        dataObjects = JSON.parse(`[${data.arrdata}]`);
      } catch (e) {
        dataObjects = null;
      }

      if (dataObjects && dataObjects[0]) {
        // Cancella la collection ImportaMacros
        await Importamacro.deleteMany({ idapp });

        // Aggiungi i record su ImportaMacros
        for (const recinv of dataObjects[0]) {
          let isnuovo = false
          let setta = false

          let recmacro = recinv;

          recmacro.idapp = idapp;

          recmacro._id = recmacro.id;

          delete recmacro.id;

          let queryprod = { idapp, _id: recmacro._id };

          try {
            let risrec = await Importamacro.findOneAndUpdate(queryprod, { $set: recmacro }, { new: true, upsert: true, strict: false });
            if (risrec) {
              imported++;
            }

          } catch (e) {
            console.error(e);
            errors++;
          }
        }
      }

      const cancella_categorie = false;

      if (cancella_categorie) {
        await CatProd.deleteMany({ idapp });
      }


      // Rileggi tutti i record di ImportaMacros
      dataObjects = await Importamacro.find({ idapp }).lean();

      console.log('*** INIZIO IMPORT PRODOTTI ... ');

      let indprod = 0;
      let newprod = 0;

      let numprod = dataObjects.length;

      for (const product of dataObjects) {
        let isnuovo = false
        let setta = false

        let importa = true;

        if (!product.title || !product.isbn)
          importa = false;

        if (importa) {
          let versGM = product.Versione ? product.Versione : '';

          // split versioneGM in array with separated ","
          let arrversGM = versGM.split(",").map(x => x.trim());

          let productInfo = {
            idapp: product.idapp,
            code: product.isbn,
            id_wp: product._id,
            name: product.title,
            description: product.description,
            short_descr: product.short_descr,
            publisher: product.Editore,
            collezione: product.Collezione,
            // author: product.Autore ? product.Autore : '',
            link: product.link ? product.link : '',
            idCatProds: [],
            idSubCatProds: [],
            //img: 'upload/products/' + product.code + '.jpg',
            image_link: product.image_link ? product.image_link : '',
            img2: product.img2 ? product.img2 : '',
            img3: product.img3 ? product.img3 : '',
            img4: product.img4 ? product.img4 : '',
            checkout_link: product.checkout_link ? product.checkout_link : '',
          }

          let versione = 0;

          console.log(indprod + '/' + numprod);


          productInfo.productTypes = [];
          // console.log('indprod', indprod, 'arrversGM', arrversGM, 'versione', product.Versione);

          for (let i = 0; i < arrversGM.length; i++) {
            // Download, DVD, Epub, Mobi, Nuovo, PDF, Streaming, Usato
            if (arrversGM[i] === 'Nuovo')
              vers = shared_consts.PRODUCTTYPE.NUOVO
            else if (arrversGM[i] === 'Usato')
              vers = shared_consts.PRODUCTTYPE.USATO;
            else if (arrversGM[i] === 'Download')
              vers = shared_consts.PRODUCTTYPE.DOWNLOAD;
            else if (arrversGM[i] === 'DVD')
              vers = shared_consts.PRODUCTTYPE.DVD;
            else if (arrversGM[i] === 'Epub')
              vers = shared_consts.PRODUCTTYPE.EPUB;
            else if (arrversGM[i] === 'Mobi')
              vers = shared_consts.PRODUCTTYPE.MOBI;
            else if (arrversGM[i] === 'PDF')
              vers = shared_consts.PRODUCTTYPE.PDF;
            else if (arrversGM[i] === 'Streaming')
              vers = shared_consts.PRODUCTTYPE.STREAMING;

            if (i === 0) {
              // salvati il primo, // nel 99,9% dei casi c'è solo 1 elemento (perchè queste sono tutte le variazioni)
              versione = vers;
            }

            productInfo.productTypes.push(vers);
          }


          if (product.Data) {
            productInfo.date_publishing = new Date(product.Data * 1000);
            // convert data to timestamp
            productInfo.date_publishing_ts = productInfo.date_publishing.getTime();
          }

          productInfo.name = productInfo.name.replace(/ - Usato$| - Nuovo$| - Epub$| - Ebook$| - Mobi$| - DVD$| - Streaming$| - Download$/, "");

          if (product.Pagine) {
            try {
              productInfo.numpages = 0;
              productInfo.numpages = parseInt(product.Pagine);
            } catch (e) {
              console.error(e);
            }
          }

          let reccateg = null;
          if (product.categories) {
            arrcat = product.categories.trim().split(',');
            for (const mycat of arrcat) {
              let mycatstr = mycat.trim();

              // Controlla se ci sono le sottocategorie:
              arrsubcat = mycatstr.trim().split('>');

              if (arrsubcat.length > 1) {
                // Ci sono delle sottocategorie
                mycatstr = arrsubcat[0].trim();
                product.subcat_name = arrsubcat[1].trim();;
              }

              // Cerca la Categoria
              reccateg = await CatProd.findOne({ idapp, name: mycatstr }).lean();
              if (!reccateg) {
                // Non esiste questo produttore, quindi lo creo !
                reccateg = new CatProd({ idapp, name: mycatstr });
                ris = await reccateg.save();
                reccateg = await CatProd.findOne({ idapp, name: mycatstr }).lean();
              }

              if (reccateg) {
                productInfo.idCatProds.push(reccateg._id);
              }
            }
          }

          // "Autore" : "Silia,Marucelli, Stefano,Cattinelli",
          let arrAuthor = [];
          if (product.Autore) {
            const arrrecauthor = product.Autore.trim().split(',');

            if (arrrecauthor.length >= 1) {
              try {
                let author = {
                  name: arrrecauthor[0].trim(),
                }
                if (arrrecauthor.length === 1) {
                  author = extractNameAndSurnameByComplete(arrrecauthor[0].trim());
                } else {
                  author.surname = arrrecauthor[1].trim();
                }
                arrAuthor.push(author);

                if (arrrecauthor.length > 1) {
                  for (let i = 2; i < arrrecauthor.length; i = i + 2) {
                    try {
                      author = {
                        name: arrrecauthor[i].trim()
                      }
                      if (arrrecauthor.length > i + 1) {
                        author.surname = arrrecauthor[i + 1].trim()
                      }
                      arrAuthor.push(author);
                    } catch (e) {
                    }
                  }
                }
                productInfo.idAuthors = [];

                for (const myauthor of arrAuthor) {
                  // Cerca l'Autore
                  recauthor = await Author.findOne({ idapp, name: myauthor.name, surname: myauthor.surname }).lean();
                  if (!recauthor) {
                    // Non esiste questo Autore, quindi lo creo !
                    recauthor = new Author({ idapp, name: myauthor.name, surname: myauthor.surname });
                    ris = await recauthor.save();
                    recauthor = await Author.findOne({ idapp, name: myauthor.name, surname: myauthor.surname }).lean();
                  }

                  if (recauthor) {
                    productInfo.idAuthors.push(recauthor._id);
                  }

                }

              } catch (e) {
                console.error(e);
              }
            }
          }

          if (product.subcat_name) {
            arrsubcat = product.subcat_name.trim().split(',');
            for (const mysubcat of arrsubcat) {
              let mysubcatstr = mysubcat.trim();

              // Cerca la Sotto Categoria
              let recsubcateg = await SubCatProd.findOne({ idapp, name: mysubcatstr }).lean();
              if (!recsubcateg) {
                // Non esiste questa Sotto Categoria, quindi la creo !
                const idCatProd = reccateg ? reccateg._id : ''
                recsubcateg = new SubCatProd({ idapp, name: mysubcatstr, idCatProd });
                ris = await recsubcateg.save();
                recsubcateg = await SubCatProd.findOne({ idapp, name: mysubcatstr, idCatProd }).lean();
              }

              if (recsubcateg) {
                productInfo.idSubCatProds.push(recsubcateg._id);
              }
            }
          }
          if (productInfo.publisher) {
            try {
              publisher = productInfo.publisher.trim();
              // Cerca la Sotto Categoria
              let recpublisher = await Publisher.findOne({ idapp, name: publisher }).lean();
              if (!recpublisher) {
                // Non esiste questo Editore, quindi la creo !
                recpublisher = new Publisher({ idapp, name: publisher });
                ris = await recpublisher.save();
                recpublisher = await Publisher.findOne({ idapp, name: publisher }).lean();
              }

              if (recpublisher) {
                productInfo.idPublisher = recpublisher._id;
              }
            } catch (e) {
              console.error(e);
            }
          }


          if (!product.hasOwnProperty('active')) {
            product.active = true;
          }

          let esisteindb = await ProductInfo.findOne({ code: productInfo.code }).lean();
          // Update ProductInfo
          let risrecInfo = await ProductInfo.findOneAndUpdate({ code: productInfo.code }, { $set: productInfo }, { new: true, upsert: true });
          if (risrecInfo) {
            product.idProductInfo = risrecInfo._id;
            recnewInfo = await ProductInfo.findOne({ code: productInfo.code }).lean();

            let { prodInfo, aggiornatoimg } = await downloadImgIfMissing(recnewInfo);

            if (aggiornatoimg) {
              await ProductInfo.findOneAndUpdate({ code: productInfo.code }, { $set: prodInfo });
            }

            if (risrecInfo._id) {
              // Record existed, so it was updated
              let arrfieldchange = tools.differentObjects(productInfo, recnewInfo);
              if (arrfieldchange && arrfieldchange.length > 0) {
                updated++;
                console.log('Changed: ', recnewInfo.name + ': ' + arrfieldchange);
              }
            }

            // Cerca il GAS
            let recGas = null;
            if (product.gas_name) {
              // Cerca il GAS
              recGas = await Gasordine.findOne({ idapp, name: product.gas_name }).lean();
            }

            if (!recGas && !!product.gas_name) {
              recGas = new Gasordine({ idapp, name: product.gas_name, active: true });
              // Non esiste questo GAS, quindi lo creo !
              ris = await recGas.save();
              recGas = await Gasordine.findOne({ idapp, name: product.gas_name }).lean();
            }

            let myproduct = {};


            let recProductExist = null;
            // ISBN e versione del prodotto sono le chiavi uniche
            let queryprod = { idProductInfo: product.idProductInfo };

            if (recGas) {
              queryprod = { ...queryprod, idGasordine: recGas._id };
            }

            recProductExist = await Product.findOne(queryprod).lean();

            if (!recProductExist) {
              isnuovo = true;
            }

            let arrvariazioni = [];
            if (isnuovo) {
              myproduct.isbn = product.isbn;
              myproduct.maxbookableGASQty = product.maxbookableGASQty ? product.maxbookableGASQty : null;
              myproduct.active = product.active;
              myproduct.idGasordine = recGas ? recGas._id : null;
              myproduct.idProductInfo = product.idProductInfo;
              myproduct.idapp = idapp;
            } else {
              arrvariazioni = recProductExist.arrvariazioni;
              if (!arrvariazioni) {
                arrvariazioni = [];
              }
            }

            // cerca l'indice della versione in arrvariazioni
            let ind = arrvariazioni.findIndex(x =>
              x.versione === versione)

            let nuovaVariazione = ind < 0;

            // 
            let variazione = {};
            if (!nuovaVariazione) {
              // Mantieni intatte questi campi del RECORD su DB:
              variazione.quantita = arrvariazioni[ind].quantita;
            }

            variazione.active = true; // ++ ??
            variazione.versione = versione;
            variazione.status = product.Stato ? product.Stato : null;
            variazione.price = product.price ? parseFloat(tools.convertPriceEurToValue(product.price)) : null;
            variazione.sale_price = product.sale_price ? parseFloat(tools.convertPriceEurToValue(product.sale_price)) : null;
            variazione.formato = product.formato ? product.formato : '';
            variazione.tipologia = product.Tipologia ? product.Tipologia : '';
            variazione.edizione = product.Edizione ? product.Edizione : '';
            variazione.eta = product.eta ? product.eta : '';
            variazione.addtocart_link = product.addtocart_link ? product.addtocart_link : '';


            if (!options.aggiornaStockQty && !nuovaVariazione) {
              // non aggiornare la Quantita in magazzino
            } else if (product.Quantita) {
              variazione.quantita = parseInt(product.Quantita);
            }
            variazione.preOrderDate = product.preOrderDate ? product.preOrderDate : null;

            // -----------------------------

            if (ind >= 0)
              arrvariazioni[ind] = variazione; // aggiorna il record "ind" in arrvariazioni
            else
              arrvariazioni.push(variazione); // aggiunge un nuovo record in arrvariazioni

            // Effettua l'ordinamento seguendo la "versione"
            arrvariazioni.sort((a, b) => a.versione - b.versione);

            // Inserisce o aggiorna il record variazione nell'array delle variazioni, in base a "versione"
            if (isnuovo) {
              myproduct.arrvariazioni = arrvariazioni;
            }

            let recold = await Product.findOne(queryprod).lean();

            let risrec = null;
            if (isnuovo) {
              // CREA PRODUCT
              risrec = await Product.findOneAndUpdate(queryprod, { $set: myproduct }, { new: true, upsert: true });
            } else {
              // Esiste già, pertanto ci aggiorno arrvariazioni
              risrec = await Product.findOneAndUpdate(queryprod, { $set: { arrvariazioni } }, { new: true, upsert: true });
            }

            let recnew = await Product.findOne(queryprod).lean();

            if (risrec) {
              if (risrec._id) {

                if (recold) {
                  // Record existed, so it was updated
                  let arrfieldchange = tools.differentObjects(recold, recnew);
                  if (arrfieldchange.length > 0) {
                    updated++;
                    let modif = '';
                    for (const field of arrfieldchange) {
                      if (field === 'arrvariazioni') {
                        modif += field + ': '

                        // Controlla quali campi sono variati tra recold.arrvariazioni e recnew.arrvariazioni
                        for (const variazione of recnew.arrvariazioni) {
                          // trova la versione in recold.arrvariazioni
                          let ind = recold.arrvariazioni.findIndex(x => x.versione === variazione.versione);

                          if (ind < 0) {
                            modif += 'Nuova Variazione [' + variazione.versione + '] ' + variazione.status + ' | Price: ' + variazione.price + ' -> Sale_Price: ' + variazione.sale_price + ' | ';
                          } else {
                            let oldvariazione = recold.arrvariazioni[ind];
                            if (oldvariazione.status !== variazione.status) {
                              modif += 'Variazione [' + oldvariazione.versione + '] ' + variazione.status + ' -> ' + variazione.status;
                            }
                            if (oldvariazione.price !== variazione.price) {
                              modif += ' | Price: ' + oldvariazione.price + ' -> ' + variazione.price;
                            }
                            if (oldvariazione.sale_price !== variazione.sale_price) {
                              modif += ' | Sale Price: ' + oldvariazione.sale_price + ' -> ' + variazione.sale_price;
                            }
                            if (oldvariazione.formato !== variazione.formato) {
                              modif += ' | Formato: ' + oldvariazione.formato + ' -> ' + variazione.formato;
                            }
                            if (oldvariazione.tipologia !== variazione.tipologia) {
                              modif += ' | Tipologia: ' + oldvariazione.tipologia + ' -> ' + variazione.tipologia;
                            }
                            if (oldvariazione.edizione !== variazione.edizione) {
                              modif += ' | Edizione: ' + oldvariazione.edizione + ' -> ' + variazione.edizione;
                            }
                            if (oldvariazione.eta !== variazione.eta) {
                              modif += ' | Età: ' + oldvariazione.eta + ' -> ' + variazione.eta;
                            }
                            if (oldvariazione.preOrderDate !== variazione.preOrderDate) {
                              modif += ' | PreOrderDate: ' + oldvariazione.preOrderDate + ' -> ' + variazione.preOrderDate;
                            }
                            if (oldvariazione.addtocart_link !== variazione.addtocart_link) {
                              modif += ' | AddToCart: ' + oldvariazione.addtocart_link + ' -> ' + variazione.addtocart_link;
                            }
                          }
                        }

                      } else {
                        modif += field + ': ' + recold[field] + ' -> ' + recnew[field] + ' | ';
                      }

                    }

                    console.log('Changed: [' + indprod + '/' + dataObjects.length + ']', productInfo.name, '[' + myproduct.idProductInfo + '] : ' + modif);
                  }
                } else {
                  newprod++;
                  console.log('Nuovo Prodotto : [' + newprod + '/' + dataObjects.length + ']', productInfo.name);
                }
              } else {
                // Record didn't exist, so it was created
                imported++;
              }
            } else {
              // risrec is null or undefined, indicating an error
              console.error('Error: ', myproduct.productInfo.name);
              errors++;
            }

            await Product.singlerecconvert_AfterImport_AndSave(idapp, recnew, isnuovo);
          } else {
            console.error('Error ProductInfo: ', product.code);
            errors++;
          }
        }

        indprod++;
      }

      console.log('*** IMPORTATI: ', imported, '*** NUOVI: ', newprod, 'AGGIORNATI = ' + updated + ' (su ' + dataObjects.length + ' RECORD)');

      return res.status(200).send({ updated, imported, errors });

    } else if (cmd === shared_consts.Cmd.PRODUCTS) {
      dataObjects = JSON.parse(`[${data.arrdata}]`);

      let updated = 0;
      let imported = 0;
      let errors = 0;

      for (const product of dataObjects) {
        let isnuovo = false
        let setta = false

        let productInfo = {
          idapp: product.idapp,
          code: product.code,
          name: product.name,
          link: product.link,
          idCatProds: [],
          idSubCatProds: [],
          img: 'upload/products/' + product.code + '.jpg',
          weight: product.weight,
          unit: tools.getIdUnitsByText(product.unit),
          productTypes: shared_consts.PRODUCTTYPE.PRODUCT,
        }

        let reccateg = null;
        if (product.cat_name) {
          arrcat = product.cat_name.trim().split(',');
          for (const mycat of arrcat) {
            let mycatstr = mycat.trim();

            // Cerca la Categoria
            reccateg = await CatProd.findOne({ idapp, name: mycatstr }).lean();
            if (!reccateg) {
              // Non esiste questo produttore, quindi lo creo !
              reccateg = new CatProd({ idapp, name: mycatstr });
              ris = await reccateg.save();
              reccateg = await CatProd.findOne({ idapp, name: mycatstr }).lean();
            }

            if (reccateg) {
              productInfo.idCatProds.push(reccateg._id);
            }
          }
        }

        if (product.subcat_name) {
          arrsubcat = product.subcat_name.trim().split(',');
          for (const mysubcat of arrsubcat) {
            let mysubcatstr = mysubcat.trim();

            // Cerca la Sotto Categoria
            let recsubcateg = await SubCatProd.findOne({ idapp, name: mysubcatstr }).lean();
            if (!recsubcateg) {
              // Non esiste questa Sotto Categoria, quindi la creo !
              const idCatProd = reccateg ? reccateg._id : ''
              recsubcateg = new SubCatProd({ idapp, name: mysubcatstr, idCatProd });
              ris = await recsubcateg.save();
              recsubcateg = await SubCatProd.findOne({ idapp, name: mysubcatstr, idCatProd }).lean();
            }

            if (recsubcateg) {
              productInfo.idSubCatProds.push(recsubcateg._id);
            }
          }
        }

        if (!product.hasOwnProperty('active')) {
          product.active = true;
        }

        if (product.code)
          delete product.code;
        if (product.name)
          delete product.name;
        if (product.link)
          delete product.link;

        let esisteindb = await ProductInfo.findOne({ code: productInfo.code }).lean();

        // Update ProductInfo
        let risrecInfo = await ProductInfo.findOneAndUpdate({ code: productInfo.code }, { $set: productInfo }, { new: true, upsert: true });
        if (risrecInfo) {
          product.idProductInfo = risrecInfo._id;

          recnewInfo = await ProductInfo.findOne({ code: productInfo.code }).lean();

          if (risrecInfo._id) {
            // Record existed, so it was updated
            let arrfieldchange = tools.differentObjects(productInfo, recnewInfo);
            if (arrfieldchange && arrfieldchange.length > 0) {
              // updated++;
              console.log('Changed: ', recnewInfo.name + ': ' + arrfieldchange);
            }
          }

          // Cerca il GAS
          let recGas = null;
          if (product.gas_name) {
            // Cerca il GAS
            recGas = await Gasordine.findOne({ idapp, name: product.gas_name }).lean();
          }

          if (!recGas && !!product.gas_name) {
            recGas = new Gasordine({ idapp, name: product.gas_name, active: true });
            // Non esiste questo GAS, quindi lo creo !
            ris = await recGas.save();
            recGas = await Gasordine.findOne({ idapp, name: product.gas_name }).lean();
          }

          let recProductExist = null;
          let queryprod = { idProductInfo: product.idProductInfo };

          if (recGas) {
            queryprod = { ...queryprod, idGasordine: recGas._id };
          }

          recProductExist = await Product.findOne(queryprod).lean();

          if (!recProductExist) {
            isnuovo = true;
          }

          if (!options.aggiornaStockQty && esisteindb && !isnuovo) {
            delete product.stockQty;
            delete product.maxbookableGASQty;
          }

          // AGGIORNA PRODUCT
          let risrec = await Product.findOneAndUpdate(queryprod, { $set: product }, { new: true, upsert: true });

          let recnew = await Product.findOne(queryprod).lean();

          if (risrec) {
            if (risrec._id) {
              // Record existed, so it was updated
              let arrfieldchange = tools.differentObjects(product, recnew);
              if (arrfieldchange.length > 0) {
                updated++;
                console.log('Changed:', product.idProductInfo + ': ' + arrfieldchange);
              }
            } else {
              // Record didn't exist, so it was created
              imported++;
            }
          } else {
            // risrec is null or undefined, indicating an error
            console.error('Error: ', product.productInfo.name);
            errors++;
          }

          await Product.singlerecconvert_AfterImport_AndSave(idapp, recnew, isnuovo);
        } else {
          console.error('Error ProductInfo: ', product.code);
          errors++;
        }

      }

      return res.status(200).send({ updated, imported, errors });

    } else if (cmd === shared_consts.Cmd.PRODUCTS_V2) {
      let mydata = `[${data.arrdata}]`;
      dataObjects = mydata.replace(/\n/g, '');
      let arrrec = [];
      try {
        arrrec = JSON.parse(dataObjects);
      } catch (e) {
        console.error("Errore durante l'analisi del JSON:", e);
        arrrec = [];
      }

      let updated = 0;
      let imported = 0;
      let errors = 0;

      let ind = 0

      const [, ...myarrshift] = arrrec;

      for (const rec of myarrshift) {

        let risprod = await extractArrayDataFromCSV(idapp, rec);
        let product = risprod.product;
        let productInfo = risprod.productInfo;



        let isnuovo = false
        let setta = false

        let reccateg = null;
        if (rec.cat_name) {
          arrcat = rec.cat_name.trim().split(',');
          for (const mycat of arrcat) {
            let mycatstr = mycat.trim();

            // Cerca la Categoria
            reccateg = await CatProd.findOne({ idapp, name: mycatstr }).lean();
            if (!reccateg) {
              // Non esiste questo produttore, quindi lo creo !
              reccateg = new CatProd({ idapp, name: mycatstr });
              ris = await reccateg.save();
              reccateg = await CatProd.findOne({ idapp, name: mycatstr }).lean();
            }

            if (reccateg) {
              productInfo.idCatProds.push(reccateg._id);
            }
          }
        }

        if (rec.subcat_name) {
          arrsubcat = rec.subcat_name.trim().split(',');
          for (const mysubcat of arrsubcat) {
            let mysubcatstr = mysubcat.trim();

            // Cerca la Sotto Categoria
            let recsubcateg = await SubCatProd.findOne({ idapp, name: mysubcatstr }).lean();
            if (!recsubcateg) {
              // Non esiste questa Sotto Categoria, quindi la creo !
              const idCatProd = reccateg ? reccateg._id : ''
              recsubcateg = new SubCatProd({ idapp, name: mysubcatstr, idCatProd });
              ris = await recsubcateg.save();
              recsubcateg = await SubCatProd.findOne({ idapp, name: mysubcatstr, idCatProd }).lean();
            }

            if (recsubcateg) {
              productInfo.idSubCatProds.push(recsubcateg._id);
            }
          }
        }


        if (!rec.hasOwnProperty('active')) {
          product.active = true;
        }

        if (productInfo.productTypes.length === 1 && productInfo.productTypes[0] === undefined) {
          productInfo.productTypes = [shared_consts.PRODUCTTYPE.PRODUCT];
        }
    
        let esisteindb = await ProductInfo.findOne({ code: productInfo.code }).lean();

        // Update ProductInfo
        let risrecInfo = await ProductInfo.findOneAndUpdate({ code: productInfo.code }, { $set: productInfo }, { new: true, upsert: true });
        if (risrecInfo) {
          product.idProductInfo = risrecInfo._id;

          recnewInfo = await ProductInfo.findOne({ code: productInfo.code }).lean();

          if (risrecInfo._id) {
            // Record existed, so it was updated
            let arrfieldchange = tools.differentObjects(productInfo, recnewInfo);
            if (arrfieldchange && arrfieldchange.length > 0) {
              // updated++;
              console.log('Changed: ', recnewInfo.name + ': ' + arrfieldchange);
            }
          }

          // Cerca il GAS
          let recGas = null;
          if (rec.gas_name) {
            // Cerca il GAS
            recGas = await Gasordine.findOne({ idapp, name: rec.gas_name }).lean();
          }

          if (!recGas && !!rec.gas_name) {
            recGas = new Gasordine({ idapp, name: rec.gas_name, active: true });
            // Non esiste questo GAS, quindi lo creo !
            ris = await recGas.save();
            recGas = await Gasordine.findOne({ idapp, name: rec.gas_name }).lean();
          }

          if (recGas) {
            if (rec.hasOwnProperty('note_ordine_gas')) {
              const note_ordine_gas = rec['note_ordine_gas'];
              await Gasordine.findOneAndUpdate({ _id: recGas._id }, { $set: { note_ordine_gas } });
            }
          }

          let recProductExist = null;
          let queryprod = { idProductInfo: product.idProductInfo };

          if (recGas) {
            queryprod = { ...queryprod, idGasordine: recGas._id };
          }

          recProductExist = await Product.findOne(queryprod).lean();

          if (!recProductExist) {
            isnuovo = true;
          }

          if (!options.aggiornaStockQty && esisteindb && !isnuovo) {
            delete product.stockQty;
            delete product.maxbookableGASQty;
          }

          // AGGIORNA PRODUCT
          let risrec = await Product.findOneAndUpdate(queryprod, { $set: product }, { new: true, upsert: true });

          let recnew = await Product.findOne(queryprod).lean();

          if (risrec) {
            if (risrec._id) {
              // Record existed, so it was updated
              let arrfieldchange = tools.differentObjects(product, recnew);
              if (arrfieldchange.length > 0) {
                updated++;
                console.log('Changed: ', product.idProductInfo + ': ' + arrfieldchange);
              }
            } else {
              // Record didn't exist, so it was created
              imported++;
            }
          } else {
            // risrec is null or undefined, indicating an error
            console.error('Error: ', product.productInfo.name);
            errors++;
          }

          await Product.singlerecconvert_AfterImport_AndSave(idapp, recnew, isnuovo);
        } else {
          console.error('Error ProductInfo: ', product.code);
          errors++;
        }

        ind++;
      }

      // L'opzione ordered: false gestisce gli errori senza interrompere l'inserimento
      /*return await Product.insertMany(dataObjects, { ordered: false })
        .then((ris) => {
     
          Product.convertAfterImportALLPROD(idapp, dataObjects).then((ris) => {
            return res.status(200).send(true);
          });
     
     
        })
        .catch((errors) => {
          console.error(errors);
          Product.convertAfterImportALLPROD(idapp).then((ris) => {
            return res.status(200).send(true);
          });
        });*/

      return res.status(200).send({ updated, imported, errors });

    }
  } catch (e) {
    console.error('e', e);
    return res.status(400).send();
  }

  return res.status(400).send();

});

router.post('/exec', authenticate, async (req, res) => {
  try {
    idapp = req.body.idapp;
    console.log('/exec idapp=', idapp, req.body.script);
    script = req.body.mydata.script;
    listafiles = req.body.mydata.listafiles;
    tokcheck = req.body.mydata.tokcheck;
    extfiles = req.body.mydata.extfiles;
    dir = req.body.mydata.dir;
    withinput = req.body.mydata.withinput;

    const TOKCHECK = 'php8.1_version_762321HSD121nJDokq@?!aFS.tar.gz'

    if (!User.isAdmin(req.user.perm) || (tokcheck !== TOKCHECK)) {
      // If without permissions, exit
      return res.status(404).send({ code: server_constants.RIS_CODE_ERR_UNAUTHORIZED, msg: '' });
    }

    let result = '';

    if (withinput)
      result = await tools.execScriptWithInputOnServer(idapp, script);
    else
      result = await tools.execScriptOnServer(idapp, script, dir, listafiles, extfiles);

    return res.send(result);
  } catch (e) {
    console.error('e', e);
    return res.status(400).send({ code: server_constants.RIS_CODE_ERR, msg: '' });
  }

});

router.post('/cloudflare', authenticate, async (req, res) => {
  try {
    idapp = req.body.idapp;
    cmd = req.body.cmd;
    tok = req.body.tok;
    zoneId = req.body.zoneId;
    tokcheck = req.body.tokcheck;
    dnsRecordId = req.body.dnsRecordId;
    record = req.body.record;
    // console.log('/cloudflare idapp=', idapp, req.body.script);

    const CloudFlareClass = require('../modules/Cloudflare.js');

    const TOKCHECK = 'php8.1_version_762321HSD121nJDokq@?!aFS.tar.gz'

    if (!User.isAdmin(req.user.perm) || (tokcheck !== TOKCHECK)) {
      // If without permissions, exit
      return res.status(404).send({ code: server_constants.RIS_CODE_ERR_UNAUTHORIZED, msg: '' });
    }

    let result = '';

    let cf = new CloudFlareClass(null);
    cf.init();

    if (cmd === "getzones") {
      result = await cf.fetchCloudflareZones(tok);
    } else if (cmd === "getDNS") {
      result = await cf.fetchDNSRecords(tok, zoneId);
    } else if (cmd === "setRecordDNS") {
      result = await cf.updateDNSRecord(tok, zoneId, dnsRecordId, record);
    } else if (cmd === "delRecordDNS") {
      result = await cf.deleteDNSRecord(tok, zoneId, dnsRecordId);
    } else if (cmd === "setCorrectIpsOnDNS") {
      result = await cf.setCorrectIpsOnDNS(record);
    } else if (cmd === "gettok") {
      result = process.env.CLOUDFLARE_TOKENS ? JSON.parse(process.env.CLOUDFLARE_TOKENS) : '';
    }

    return res.send(result);
  } catch (e) {
    console.error('e', e);
    return res.status(400).send({ code: server_constants.RIS_CODE_ERR, msg: '' });
  }

});

router.post('/miab', authenticate, async (req, res) => {
  try {
    idapp = req.body.idapp;
    cmd = req.body.cmd;
    record = req.body.record;
    tokcheck = req.body.tokcheck;

    const MailinaboxClass = require('../modules/Mailinabox.js');

    const TOKCHECK = 'php8.1_version_762321HSD121nJDokq@?!aFS.tar.gz'

    if (!User.isAdmin(req.user.perm) || (tokcheck !== TOKCHECK)) {
      // If without permissions, exit
      return res.status(404).send({ code: server_constants.RIS_CODE_ERR_UNAUTHORIZED, msg: '' });
    }

    let result = '';

    let miab = new MailinaboxClass(null);
    miab.init();

    if (cmd === "getEmails") {
      result = await miab.MIAB_getEmails(record);
    } else if (cmd === "removeEmails") {
      result = await miab.removeEmail(record);
    } else if (cmd === "addEmail") {
      result = await miab.addEmail(record);
    } else if (cmd === "setMailUserPassword") {
      result = await miab.setMailUserPassword(record);
    }

    return res.send(result);
  } catch (e) {
    console.error('e', e);
    return res.status(400).send({ code: server_constants.RIS_CODE_ERR, msg: '' });
  }

});

module.exports = router;
