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 Macro = require('../modules/Macro'); // Importa la classe Macro

const fs = require('fs'); // 👈 Usa il modulo promises

const { City } = require('../models/city');
const Product = require('../models/product');
const Inventariogm = require('../models/inventariogm');
const Importamacro = require('../models/importamacro');
const ImportaDescr = require('../models/importadescr');
const ImportaIsbn = require('../models/importaisbn');
const CatProd = require('../models/catprod');
const Collana = require('../models/collana');
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 AmazonBookScraper = require('../modules/Scraping');

const { Catalog } = require('../models/catalog');
const { RaccoltaCataloghi } = require('../models/raccoltacataloghi');

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

const path = require('path');

const gs = require('ghostscript4js');

const { PDFDocument, rgb } = require('pdf-lib');

const pdf = require('pdf-parse');

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

const multer = require('multer');

const DIR_PDF_IN = __dirname + '/upload/files_input/';
// const DIR_PDF_OUT = __dirname + '/upload/files_output/';

const upload = multer({ dest: DIR_PDF_IN });

const util = require('util');
const cwd = process.cwd();

const { exec } = require('child_process');

const execPromise = util.promisify(exec);

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

const genPdf = new GenPdf();

let genPdfLaunched = false;
function launchGenPdfIfNeeded() {
  if (!genPdfLaunched) {
    genPdfLaunched = true;
    genPdf.launch();
  }
}

/*async function updateProductInfo(recproductInfoAttuale, product, idapp, mycatstr) {
  if (!recproductInfoAttuale || !mycatstr) return recproductInfoAttuale;

  let idArgomentoNum = null;

  let productInfo = null;

  if (product.ListaArgomenti) {
    idArgomentoNum = parseInt(product.ListaArgomenti);
    productInfo = { ...recproductInfoAttuale, idArgomento: idArgomentoNum };
  } else {
    productInfo = { ...recproductInfoAttuale };
  }

  let reccatprod = await findOrCreateCatProd(idapp, idArgomentoNum, mycatstr);

  if (reccatprod) {
    updateProductInfoCatProds(productInfo, reccatprod);
  }

  return productInfo;
}*/

async function findOrCreateCatProd(idapp, idArgomento, DescrArgomento) {
  let reccatprod = null;
  if (idArgomento) {
    reccatprod = await CatProd.findOne({ idapp, idArgomento }).lean();
  }

  if (!reccatprod) {
    reccatprod = await CatProd.findOne({ idapp, name: DescrArgomento }).lean();
    if (reccatprod) {
      if (idArgomento) {
        await CatProd.findOneAndUpdate(
          { _id: reccatprod._id },
          { $set: { idArgomento } },
          {
            returnDocument: 'after',
            upsert: false,
          }
        );
      }
    } else {
      if (idArgomento) {
        try {
          reccatprod = new CatProd({ idapp, idArgomento, name: DescrArgomento });
          await reccatprod.save();
        } catch (e) {
          console.error('Errore nella creazione di CatProd:', e);
          return null;
        }
      }
    }
  }

  return reccatprod;
}

function updateProductInfoCatProds(productInfo, reccatprod) {
  if (productInfo) {
    // Controllo che nell'array productInfo.idCatProds ci sia esattamente 1 record e che sia uguale a reccatprod._id
    const cond3 =
      Array.isArray(productInfo.idCatProds) &&
      productInfo.idCatProds.length > 0 &&
      productInfo.idCatProds[0].toString() !== reccatprod._id.toString();
    const isChanged =
      !Array.isArray(productInfo.idCatProds) || // Assicurati che sia un array
      productInfo.idCatProds.length !== 1 || // L'array deve contenere esattamente 1 elemento
      cond3; // Il primo elemento deve essere uguale a reccatprod._id

    if (isChanged) {
      productInfo.idCatProds = [reccatprod._id];
      console.log('ARGOMENTO VARIATO!', reccatprod.name, ' Libro:', productInfo.name);
    }
  }
}
/*
  Quando utilizzi Ghostscript per comprimere un PDF e desideri controllare la qualità di stampa, puoi modificare i parametri dell'opzione -dPDFSETTINGS per ottenere risultati migliori per scopi di stampa. 
  Le seguenti opzioni sono disponibili per -dPDFSETTINGS:

  Opzioni di -dPDFSETTINGS
  /screen: Buona per la visualizzazione su schermo; bassa qualità e dimensione del file ridotta.
  /ebook: Ottimizza il PDF per la lettura su ebook; qualità media e dimensione media.
  /printer: Ottimizza il PDF per la stampa di qualità; migliora la risoluzione rispetto a /ebook.
  /prepress: Ottimizza per la stampa di alta qualità; ideale per progetti di stampa professionali.
  /default: Usa impostazioni predefinite; generalmente fornisce un buon equilibrio tra qualità e dimensione.
  */

async function compressPdf(inputFile, outputFile, compressione) {
  try {
    const tempFolder = path.join(cwd, 'temp');
    const hasTempFolder = await tools.isFileExistsAsync(tempFolder);

    if (!hasTempFolder) {
      console.log('creo directory', tempFolder);
      await fs.mkdir(tempFolder); // Usa la versione promessa di mkdir
      console.log('✅ directory creata', tempFolder);
    }

    // Valori ammessi per -dPDFSETTINGS di Ghostscript
    const validSettings = ['screen', 'printer', 'high', 'maximum'];
    if (!validSettings.includes(compressione)) {
      console.warn(`Compressione '${compressione}' non valida, uso 'ebook'`);
      compressione = 'ebook';
    }

    const origSize = await tools.getSizeFile(inputFile);

    let add = '';

    // Eventualmente......
    const in300dpi = false;
    if (in300dpi) {
      add += '-dDPIx=300 -dDPIy=300';
    }

    // Costruisci comando Ghostscript per la compressione PDF
    const gsCommand = [
      'gs',
      '-sDEVICE=pdfwrite',
      '-dCompatibilityLevel=1.4',
      `-dPDFSETTINGS=/${compressione}`,
      '-dNOPAUSE',
      '-dQUIET',
      '-dBATCH',
      `-sOutputFile="${outputFile}"`,
      `"${inputFile}"`,
      '-dDownsampleColorImages=true -dColorImageResolution=72',
    ].join(' ');

    console.log('Compressione del PDF in corso...');
    console.log('gsCommand', gsCommand);

    // Esegui il comando per la compressione
    await execPromise(gsCommand);

    // Calcola la percentuale di compressione
    const newSize = await tools.getSizeFile(outputFile);
    const percent = Math.round(((origSize - newSize) / origSize) * 100);
    console.log(`Il file compresso è circa il ${percent}% più piccolo dell'originale`);

    console.log(`PDF compresso e salvato come '${outputFile}'`);
  } catch (error) {
    console.error('Errore durante la compressione:', error);
  }
}

async function compressPdfWithPs2Pdf(inputFile, outputFile, compression = 'ebook') {
  try {
    // Verifica se il file di input esiste
    if (!(await tools.isFileExistsAsync(inputFile))) {
      console.error(`Il file di input '${inputFile}' non esiste`);
    }

    // Costruisci il comando ps2pdf
    const ps2pdfCommand = `ps2pdf -dPDFSETTINGS=/${compression} "${inputFile}" "${outputFile}"`;

    console.log(`Eseguendo: ${ps2pdfCommand}`);

    // Esegui il comando ps2pdf
    await execPromise(ps2pdfCommand);

    console.log(`PDF compresso con successo: ${outputFile}`);
  } catch (error) {
    console.error('Errore durante la compressione del PDF:', error);
  }
}

// DIAGNOSI COMPLETA DEL PROBLEMA
async function diagnosePDFProblem() {
  console.log('=== DIAGNOSI COMPLETA SISTEMA ===');

  // 1. Test ambiente Node.js
  console.log('Node.js version:', process.version);
  console.log('Platform:', process.platform);
  console.log('Architecture:', process.arch);
  console.log('Current working directory:', process.cwd());

  // 2. Test moduli disponibili
  try {
    console.log('Testing gs module...');
    console.log('gs object:', typeof gs, Object.keys(gs || {}));
  } catch (error) {
    console.log('gs module error:', error.message);
  }

  // 3. Test comando di sistema
  const { exec } = require('child_process');
  const util = require('util');
  const execAsync = util.promisify(exec);

  try {
    console.log('Testing gs command from system...');
    const { stdout, stderr } = await execAsync('gs -version');
    console.log('GS Version stdout:', stdout);
    console.log('GS Version stderr:', stderr);
  } catch (error) {
    console.log('System gs command failed:', error.message);
  }

  // 4. Test scrittura file
  const fs = require('fs').promises;
  const path = require('path');
  const testFile = path.join(process.cwd(), 'test_write.txt');

  try {
    await fs.writeFile(testFile, 'test content');
    console.log('File write test: SUCCESS');
    await fs.unlink(testFile);
  } catch (error) {
    console.log('File write test: FAILED -', error.message);
  }
}

// ALTERNATIVA 1: Usando child_process direttamente
async function convertPDF_ChildProcess(inputFile, outputFile, width, height, compressionLevel = 'screen') {
  const { spawn } = require('child_process');
  const path = require('path');

  console.log('=== CONVERSIONE CON CHILD_PROCESS E COMPRESSIONE ===');

  // Verifica input
  if (!(await tools.isFileExistsAsync(inputFile))) {
    throw new Error(`File input non trovato: ${inputFile}`);
  }

  // Assicurati che la directory output esista
  const outputDir = path.dirname(outputFile);
  const fs = require('fs').promises;
  try {
    await fs.mkdir(outputDir, { recursive: true });
  } catch (error) {
    // Directory già esistente, ok
  }

  // const widthPt = Math.round(width * 28.34646);
  // const heightPt = Math.round(height * 28.34646);
  const widthPt = Math.round(width * 28.34646 * 10);
  const heightPt = Math.round(height * 28.34646 * 10);

  // Parametri di compressione ottimizzati
  const compressionSettings = {
    maximum: [
      '-dPDFSETTINGS=/screen',
      '-dDownsampleColorImages=true',
      '-dColorImageResolution=72',
      '-dDownsampleGrayImages=true',
      '-dGrayImageResolution=72',
      '-dDownsampleMonoImages=true',
      '-dMonoImageResolution=72',
    ],
    high: [
      '-dPDFSETTINGS=/ebook',
      '-dDownsampleColorImages=true',
      '-dColorImageResolution=150',
      '-dDownsampleGrayImages=true',
      '-dGrayImageResolution=150',
    ],
    printer: ['-dPDFSETTINGS=/printer', '-dDownsampleColorImages=true', '-dColorImageResolution=300'],
    screen: [
      '-dPDFSETTINGS=/screen',
      '-dDownsampleColorImages=true',
      '-dColorImageResolution=96',
      '-dDownsampleGrayImages=true',
      '-dGrayImageResolution=96',
    ],
  };

  return new Promise((resolve, reject) => {
    const args = [
      '-sDEVICE=pdfwrite',
      '-dCompatibilityLevel=1.4',
      '-dNOPAUSE',
      '-dQUIET',
      '-dBATCH',
      '-dSAFER',

      // Parametri di compressione
      ...(compressionSettings[compressionLevel] || compressionSettings['screen']),
      '-dCompressFonts=true',
      '-dSubsetFonts=true',
      '-dColorImageFilter=/DCTEncode',
      '-dGrayImageFilter=/DCTEncode',
      '-dEmbedAllFonts=true',

      // Dimensioni pagina
      `-g${widthPt}x${heightPt}`,
      '-dFIXEDMEDIA',
      // '-dPDFFitPage',

      // Output
      `-sOutputFile=${outputFile}`,
      inputFile,
    ];

    console.log('Spawning gs with compression args:', args.join(' '));

    const gsProcess = spawn('gs', args, {
      stdio: ['ignore', 'pipe', 'pipe'],
      shell: process.platform === 'win32',
    });

    let stdout = '';
    let stderr = '';

    gsProcess.stdout.on('data', (data) => {
      stdout += data.toString();
      if (stdout.length < 1000) {
        // Evita log troppo lunghi
        console.log('GS OUT:', data.toString().trim());
      }
    });

    gsProcess.stderr.on('data', (data) => {
      stderr += data.toString();
      if (stderr.length < 1000) {
        console.log('GS ERR:', data.toString().trim());
      }
    });

    gsProcess.on('close', async (code) => {
      console.log(`GS process closed with code: ${code}`);

      if (code === 0) {
        // Attendi e verifica
        setTimeout(async () => {
          try {
            const exists = await tools.isFileExistsAsync(outputFile);
            if (exists) {
              // Verifica dimensioni per confermare compressione
              try {
                const originalStats = await tools.getFileStatsAsync(inputFile);
                const newStats = await tools.getFileStatsAsync(outputFile);
                const compressionRatio = (((originalStats.size - newStats.size) / originalStats.size) * 100).toFixed(1);

                console.log(`📁 File originale: ${(originalStats.size / 1024 / 1024).toFixed(2)} MB`);
                console.log(`📁 File compresso: ${(newStats.size / 1024 / 1024).toFixed(2)} MB`);
                console.log(`🗜️ Compressione: ${compressionRatio}%`);
                console.log('✅ SUCCESS: File generato e compresso');
              } catch (statsError) {
                console.log('Warning: impossibile calcolare statistiche compressione');
              }

              resolve(outputFile);
            } else {
              console.log('❌ FAIL: File non generato nonostante exit code 0');
              reject(new Error('File non generato nonostante successo processo'));
            }
          } catch (error) {
            reject(error);
          }
        }, 1000);
      } else {
        reject(new Error(`Ghostscript failed with code ${code}: ${stderr}`));
      }
    });

    gsProcess.on('error', (error) => {
      console.log('GS process error:', error);
      reject(new Error(`Failed to start Ghostscript: ${error.message}`));
    });
  });
}

async function extractPdfInfo(inputFile) {
  // Estrai le dimensioni delle pagine utilizzando pdf-lib
  const existingPdfBytes = fs.readFileSync(inputFile);
  const pdfDoc = await PDFDocument.load(existingPdfBytes);

  // Ottieni informazioni sulle dimensioni delle pagine
  const pages = pdfDoc.getPages();
  const pageInfo = pages.map((page) => {
    const { width, height } = page.getSize();
    return {
      width: width, // in punti
      height: height, // in punti
    };
  });

  // Estrai informazioni testuali e numero di pagine utilizzando pdf-parse
  const dataBuffer = fs.readFileSync(inputFile);
  const data = await pdf(dataBuffer);

  const dpiInfo = {
    numPages: data.numpages,
    pageInfo: pageInfo,
  };

  console.log('DPI info might require image extraction (not available directly):');
  console.log('Number of Pages:', dpiInfo.numPages);
  console.log('Page Dimensions (in points):', dpiInfo.pageInfo);
}

async function convertPDF_PdfLib(idapp, inputFile, outputFile, options) {
  if (!(await tools.isFileExistsAsync(inputFile))) {
    throw new Error(`Il file di input non esiste: ${inputFile}`);
  }

  console.log('START convertPDF_PdfLib...');

  try {
    options.filenameIn = inputFile;
    options.filenameOut = outputFile;
    const uscita = await ConvertPDF_Generatore(options, options.stampa);

    return uscita;
  } catch (e) {
    console.error('Errore: ', e.message);
    return '';
  }
}

async function leggiDimensioniPdf(filePath) {
  const pdfBytes = await fs.promises.readFile(filePath);
  const pdfDoc = await PDFDocument.load(pdfBytes);

  const pages = pdfDoc.getPages();
  const primaPagina = pages[0];

  const { width, height } = primaPagina.getSize();

  console.log(
    `Dimensioni prima pagina: larghezza = ${tools.arrotondaA2Decimali(
      (width / 72) * 25.4
    )} mm, altezza = ${tools.arrotondaA2Decimali((height / 72) * 25.4)} mm`
  );

  return { width, height };
}

async function ConvertPDF_Generatore(options, instampa) {
  let fileout = '';
  let fileout_compressed = '';
  let suffisso_filename = '';

  if (!options.filenameIn) {
    return { err: 'Nessun file passato in Ingresso.' };
  }

  let marginTop = instampa ? parseFloat(options.print_top) : 0;
  let marginRight = instampa ? parseFloat(options.print_right) : 0;
  let marginBottom = instampa ? parseFloat(options.print_bottom) : 0;
  let marginLeft = instampa ? parseFloat(options.print_left) : 0;

  if (instampa) {
    suffisso_filename = '_stampabile_generato';
  } else {
    suffisso_filename = '_generato';
  }

  let outputFilename = suffisso_filename
    ? tools.aggiungiSuffissoAlNomeFile(options.filenameOut, suffisso_filename)
    : options.filenameOut;

  // controlla se outputFilename non ha directory allora gliela aggiungo
  if (!path.dirname(outputFilename)) {
    outputFilename = path.join(options.dir_out, outputFilename);
  }

  const outputFullPathFileName = outputFilename;

  await leggiDimensioniPdf(options.filenameIn);

  try {
    // Leggi il PDF originale
    const existingPdfBytes = await fs.promises.readFile(options.filenameIn);
    const srcPdfDoc = await PDFDocument.load(existingPdfBytes); // Documento sorgente
    const destPdfDoc = await PDFDocument.create(); // Nuovo documento vuoto

    const pages = srcPdfDoc.getPages();

    for (let i = 0; i < pages.length; i++) {
      const page = pages[i];
      //  punti PDF (pt), dove 1 punto = 1/72 di pollice.
      const { width, height } = page.getSize();

      // CONVERTIli in mm e stampa su console
      console.log(`Dimensione pagina ${i + 1}: ${(width / 72) * 25.4} mm x ${(height / 72) * 25.4} mm`);

      const newWidth = width - marginLeft - marginRight;
      const newHeight = height - marginTop - marginBottom;

      // Embed della pagina originale nel nuovo documento
      const embeddedPages = await destPdfDoc.embedPdf(srcPdfDoc, [i]); // Embeddiamo la pagina i-esima
      const embeddedPage = embeddedPages[0]; // Otteniamo l'oggetto embedded

      // Aggiungi una nuova pagina alla stessa dimensione dell’originale
      const newPage = destPdfDoc.addPage([width, height]);

      // Disegna la pagina embedded nella nuova pagina
      newPage.drawPage(embeddedPage, {
        x: marginLeft,
        y: marginBottom,
        width: newWidth,
        height: newHeight,
      });
    }

    // Salva il nuovo PDF
    const pdfBytes = await destPdfDoc.save();

    const dirUscita = path.dirname(outputFullPathFileName);
    if (!(await tools.isDirectoryAsync(dirUscita))) {
      await fs.promises.mkdir(dirUscita, { recursive: true });
    }

    await fs.promises.writeFile(outputFullPathFileName, pdfBytes);

    fileout = outputFullPathFileName;
    extractPdfInfo(fileout);

    // Elimina il file compresso precedente...
    fileOLD_compressed = tools.removeFileExtension(fileout) + `_compressed.pdf`;
    if (await tools.isFileExistsAsync(fileOLD_compressed)) {
      await tools.deleteFile(fileOLD_compressed);
    }

    if (options.compressione) {
      const mostrainfo = true;
      fileout_compressed = tools.removeFileExtension(fileout) + `_compressed.pdf`;
      await diagnosePDFProblem();

      // await compressPdf(fileout, fileout_compressed, options.compressione);
      // await compressPdfWithPs2Pdf(fileout, fileout_compressed, options.compressione);
      await convertPDF_ChildProcess(fileout, fileout_compressed, options.width, options.height, options.compressione);

      // if (mostrainfo) extractPdfInfo(fileout_compressed);
    }
  } catch (error) {
    const log = `Errore durante la creazione del PDF: (instampa = ${instampa}): ` + error.message;
    console.error(log);
    return {
      err: log,
      fileout: tools.removePathDirByFileName(options.idapp, fileout),
      fileout_compressed: tools.removePathDirByFileName(options.idapp, fileout_compressed),
    };
  }

  return {
    fileout: tools.removePathDirByFileName(options.idapp, fileout),
    fileout_compressed: tools.removePathDirByFileName(options.idapp, fileout_compressed),
    filesize: await tools.getSizeFile(fileout),
    filesize_compressed: fileout_compressed ? await tools.getSizeFile(fileout_compressed) : 0,
  };
}

router.post('/online-pdf', authenticate, async (req, res) => {
  console.log('/online-pdf');

  try {
    launchGenPdfIfNeeded(); // Ensure GenPdf is launched before proceeding

    const risout = await GenPdf.onlinePdf(req.body);

    return res.status(200).send(risout);
  } catch (e) {
    console.error('Err Online-pdf', e.message);
  }
});

async function JoinPDFCatalogs(raccolta, cataloghi, options, outputFile, stampa) {
  try {
    // Per ogni catalogo prendi il suo PDF Generato

    const pdfDoc = await PDFDocument.create();

    let numcat = 0;

    // Aggiungi eventuale PDF di copertina

    if (raccolta.pdf_copertina) {
      let dirmain = '';
      if (!tools.sulServer()) {
        dirmain = server_constants.DIR_PUBLIC_LOCALE;
      }

      const myfile = tools.fixFilePath(
        path.join(options.mydir + dirmain + '/' + options.dir_out, raccolta.pdf_copertina?.imagefile)
      );
      console.log(' copertina: ' + myfile);
      if (await tools.isFileExistsAsync(myfile)) {
        const pdfBytes = await fs.promises.readFile(myfile);
        const pdf = await PDFDocument.load(pdfBytes);
        const pages = pdf.getPages();
        const copiedPages = await pdfDoc.copyPages(
          pdf,
          pages.map((p, i) => i)
        );
        for (let page of copiedPages) {
          pdfDoc.addPage(page);
        }
        console.log('   Aggiungo la copertina ' + myfile);
      }
    }

    for (let id_catalog of cataloghi) {
      let catalog = await Catalog.findOne({ _id: id_catalog });
      if (catalog) {
        let filename = stampa ? catalog.pdf_online_stampa : catalog.pdf_online;
        if (filename) {
          let myfile = tools.fixFilePath(options.mydir + '/' + filename);
          if (await tools.isFileExistsAsync(myfile)) {
            const filenameOnly = path.parse(myfile).base;

            numcat++;
            console.log('   Aggiungo il catalogo [' + numcat + '] ' + filenameOnly + ' ...');

            const pdfBytes = await fs.promises.readFile(myfile);
            const pdf = await PDFDocument.load(pdfBytes);
            const pages = pdf.getPages();
            const copiedPages = await pdfDoc.copyPages(
              pdf,
              pages.map((p, i) => i)
            );
            for (let page of copiedPages) {
              pdfDoc.addPage(page);
            }
          }
        } else {
          console.log('ATTENZIONE! Catalogo non ancora Generato ! ', catalog.title);
        }
      }
    }

    // Raccolta salvata !
    const pdfBytes = await pdfDoc.save();
    await fs.promises.writeFile(outputFile, pdfBytes);
    // scrivi il percorso relativo e nomefile sul DB

    const outputFilename = path.basename(outputFile);
    const outputPath = path.join(options.dir_out, outputFilename);

    if (await tools.isFileExistsAsync(outputFile)) {
      console.log('✅ Catalogo Completo Generato correttamente ! ', outputFile);
    } else {
      console.log('❌ Catalogo non generato ! ', outputFile);
    }

    const ris = {
      outputPath,
    };

    return ris;
  } catch (e) {
    console.error('Error: ', e);
  }

  return {};
}

router.post('/join-pdf', authenticate, async (req, res) => {
  console.log('/join-pdf');

  idapp = req.body.idapp;
  options = req.body.options;
  options.idapp = idapp;
  options.mydir = tools.getdirByIdApp(idapp);

  try {
    const mydirpath = tools.getdirByIdApp(options.idapp);
    const full_dir_out = tools.fixFilePath(path.join(mydirpath, options.dir_out));
    await fs.promises.mkdir(full_dir_out, { recursive: true });

    // Aggiorna il PDF OnLine, copiando il file da Generato a OnLine
    let raccolta = await RaccoltaCataloghi.findOne({ _id: options.id_raccolta });

    if (raccolta && raccolta.nomefile_da_generare) {
      cataloghi = raccolta.lista_cataloghi;

      let outputFile = path.join(
        full_dir_out,
        tools.removeFileExtension(raccolta.nomefile_da_generare) + '_generato.pdf'
      );

      if (options.stampa) {
        outputFileStampa =
          path.join(full_dir_out, path.basename(tools.removeFileExtension(outputFile))) + '_stampabile.pdf';
        // Creazione file per STAMPA
        const ris_stampa = await JoinPDFCatalogs(raccolta, cataloghi, options, outputFileStampa, true);
        if (ris_stampa) {
          raccolta.pdf_generato_stampa = ris_stampa.outputPath;
          let myfilecheckstampa = path.join(mydirpath, ris_stampa.outputPath);
          raccolta.pdf_generato_stampa_size = await tools.getSizeFile(myfilecheckstampa);
          raccolta.data_generato_stampa = tools.getDateNow();
        }
      } else {
        // Creazione file per WEB
        const ris = await JoinPDFCatalogs(raccolta, cataloghi, options, outputFile, false);
        if (ris) {
          raccolta.pdf_generato = ris.outputPath;
          let myfilecheck = path.join(mydirpath, ris.outputPath);
          raccolta.pdf_generato_size = await tools.getSizeFile(myfilecheck);
          raccolta.data_generato = tools.getDateNow();
        }
      }

      if (options.metti_online) {
        if (options.stampa) {
          raccolta.pdf_online_stampa = raccolta.pdf_generato_stampa.replace('_generato', '');
        } else {
          raccolta.pdf_online = raccolta.pdf_generato.replace('_generato', '');
        }
        const fileDest = options.mydir + raccolta.pdf_online;
        await fs.promises.writeFile(fileDest, pdfBytes);

        let size = await tools.getSizeFile(FileDest);

        if (options.stampa) {
          raccolta.pdf_online_stampa_size = size;
        } else {
          raccolta.pdf_online_size = size;
        }
      }

      await raccolta.save();

      risout = { raccolta: raccolta._doc };
    }

    // risout

    return res.status(200).send(risout);
  } catch (e) {
    console.error('Err join-pdf', e.message);
  }
});

// Endpoint POST per la conversione del PDF
router.post('/convert-pdf', upload.single('pdf'), async (req, res) => {
  if (!req.file) {
    return res.status(400).send('No file uploaded.');
  }

  const inputFile = req.file.path;
  const {
    width,
    height,
    compressione,
    dir_out,
    file_out,
    idapp,
    print_top = '0',
    print_right = '0',
    print_bottom = '0',
    print_left = '0',
    stampa,
    salvasufiledascaricare = 'false',
  } = req.body;

  if (!width) {
    await fs.promises.unlink(inputFile);
    return res.status(400).send('Width parameter is required');
  }

  const options = {
    width,
    height,
    compressione,
    dir_out: tools.getdirByIdApp(idapp) + '/' + dir_out,
    file_out,
    idapp,
    print_top,
    print_right,
    print_bottom,
    print_left,
    stampa: stampa === '1',
  };

  let invia_file_convertito = false;
  if (!options.file_out || options.file_out === '') {
    options.file_out = `${tools.removeFileExtension(req.file.originalname)}-converted.pdf`;
    invia_file_convertito = true;
  }
  let outputFile = path.join(options.dir_out, options.file_out);

  try {
    await fs.promises.mkdir(DIR_PDF_IN, { recursive: true });
    await fs.promises.mkdir(options.dir_out, { recursive: true });

    // Converti il PDF
    const risout = await convertPDF_PdfLib(idapp, inputFile, outputFile, options);

    if (salvasufiledascaricare === 'true') {
      // Invia il file come download
      return res.download(outputFile, options.file_out, async (err) => {
        await cleanupFiles(inputFile, outputFile);
        if (err) {
          console.error("Errore durante l'invio del file:", err.message || err);
          if (!res.headersSent) {
            return res.status(500).send("Errore durante l'invio del file convertito");
          }
        }
      });
    } else {
      // Non inviare file, solo risposta JSON
      await cleanupFiles(inputFile, ''); // pulisci solo inputFile
      return res.status(200).send(risout);
    }
  } catch (error) {
    console.error('Errore durante la conversione:', error);
    await cleanupFiles(inputFile, '');
    if (!res.headersSent) {
      return res.status(500).send(`Errore durante la conversione del PDF: ${error.message}`);
    }
  }
});

async function cleanupFiles(inputFile, outputFile) {
  if (inputFile) {
    await tools.deleteFile(inputFile).catch((err) => {
      console.error('Errore durante la rimozione del file di INPUT:', err);
    });
  }
  if (outputFile) {
    await tools.deleteFile(outputFile).catch((err) => {
      console.error('Errore durante la rimozione del file di output:', err);
    });
  }
}

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) => {
      if (!!item) {
        return res.status(200).send();
      } else {
        return res.status(400).send();
      }
    })
    .catch((err) => {
      console.log('ERR:', err);
      return res.status(400).send();
    });
});

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

async function completaSettaggioProduct_AndProductInfo(arrcampi_productInfo, arrcampi_product, rec, product) {
  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) {
          product.productInfo.weight = ris1.weight;
          product.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) {
          product.productInfo.weight_lordo = ris2.weight;
          product.productInfo.unit_lordo = ris2.unit;
        }
      }
    }

    if (rec.hasOwnProperty('link_scheda')) {
      if (fixURL(rec['link_scheda'])) product.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) product.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.productInfo.code) {
      product.productInfo.imagefile = product.productInfo.code + '.jpg';
    } else {
      if (rec.hasOwnProperty('img')) {
        if (rec['img']) {
          product.productInfo.imagefile = rec['img'];
        } else {
          product.productInfo.imagefile = '';
        }
      }
    }

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

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

  return { product };
}

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 product = {
      productInfo: {
        idCatProds: [],
        idSubCatProds: [],
      },
      idapp,
    };

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

    for (const campoobj of arrcampi_productInfo) {
      // TODO: controlla che il campo rec[campoobj.name] esista anche se minuscolo/maiuscolo
      const mykey = Object.keys(rec).find((key) => key.toLowerCase() === campoobj.name.toLowerCase());
      if (mykey) {
        let myval = tools.ripulisciCampo(rec[mykey]);
        product.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];
    }

    for (const campoconvertiti of shared_consts.CONVERTI_CAMPO) {
      if (rec.hasOwnProperty(campoconvertiti.convertito)) {
        product[campoconvertiti.originale] = rec[campoconvertiti.convertito];
      }
    }

    // Se trovi questi campi, li converti
    

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

    /*
      // 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: '' };
  }
}

function getvalueByJsonText(valore) {
  if (valore && valore['#text']) {
    if (valore['#text']) return valore['#text'];
    else return value;
  }

  return null;
}

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_DESCRELINKSITOWEB) {
      let updated = 0;
      let imported = 0;
      let errors = 0;

      const ripopola = true;

      dataObjects = null;

      let myarr = null;

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

        myarr = dataObjects[0].item_list.item;
      } catch (e) {
        dataObjects = null;
      }

      if (myarr && ripopola) {
        console.log('*** INIZIO IMPORT RIPOPOLAMENTO ... ', myarr.length);

        // Cancella la collection ImportaMacros
        await ImportaDescr.deleteMany({ idapp });

        // Aggiungi i record su ImportaDescr
        for (const recinv of myarr) {
          let isnuovo = false;
          let setta = false;

          let recmacro = recinv;

          recmacro.idapp = idapp;

          if (recmacro.ean && recmacro.ean['#text']) {
            recmacro._id = recmacro.ean['#text'];
            recmacro.code = recmacro._id;
            recmacro.title = getvalueByJsonText(recmacro.titolo);

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

            try {
              // non inserisce nuovi record, se non lo trova ! perché sono troppi !
              let risrec = await ImportaDescr.findOneAndUpdate(
                queryprod,
                { $set: recmacro },
                { new: true, upsert: true, strict: false }
              );
              if (risrec) {
                imported++;
                // if (imported > 1000)
                //   break;
                if (imported % 100 === 0) console.log('importato ', imported, 'su ', myarr.length);
              }
            } catch (e) {
              console.error(e);
              errors++;
            }
          }
        }
      }

      if (!myarr && ripopola) {
        return res.status(400).send(data.arrdata);
      }

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

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

      let indprod = 0;
      let newprod = 0;

      let numprod = dataObjects.length;

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

        let importa = true;

        if (!productImported.code) importa = false;

        if (importa) {
          let productInfo = {
            idapp: productImported.idapp,
            code: productImported.code,
          };

          const myproduct = await Product.findOne({ 'productInfo.code': productInfo.code });

          // IMPOSTA I VALORI SOLO SE NON ESISTONO ! ALTRIMENTI LASCIA QUELLI GIA' IMPORTATI (O MODIFICATI)

          if (getvalueByJsonText(productImported.url)) {
            if ((myproduct && !myproduct.productInfo.link_macro) || !myproduct.productInfo)
              productInfo.link_macro = getvalueByJsonText(productImported.url);
          }
          if (getvalueByJsonText(productImported.descrizione)) {
            if ((myproduct && !myproduct.productInfo.descrizione_breve_macro) || !myproduct.productInfo)
              productInfo.descrizione_breve_macro = getvalueByJsonText(productImported.descrizione);
          }
          if (getvalueByJsonText(productImported.descrizione_completa)) {
            if ((myproduct && !myproduct.productInfo.descrizione_completa_macro) || !myproduct.productInfo)
              productInfo.descrizione_completa_macro = getvalueByJsonText(productImported.descrizione_completa);
          }
          if (getvalueByJsonText(productImported.sottotitolo)) {
            if ((myproduct && !myproduct.productInfo.sottotitolo) || !myproduct.productInfo)
              productInfo.sottotitolo = getvalueByJsonText(productImported.sottotitolo);
          }
          if (getvalueByJsonText(productImported.titolo)) {
            if ((myproduct && !myproduct.productInfo.name) || !myproduct.productInfo)
              productInfo.name = getvalueByJsonText(productImported.titolo);
          }

          const pagine = getvalueByJsonText(productImported.pagine);

          let recisbn = {};

          const trovato = await ImportaIsbn.findOne({ isbn: productImported.code }).lean();
          if (trovato) {
            // togli a recisbn l'_id
            delete trovato._id;
            recisbn = trovato;
          }

          if (pagine && pagine !== '0') {
            recisbn.Pagine = pagine;
          }

          recisbn.link_macro = productInfo.link_macro;
          recisbn.descrizione_breve_macro = productInfo.descrizione_breve_macro;
          recisbn.descrizione_completa_macro = productInfo.descrizione_completa_macro;
          recisbn.sottotitolo = productInfo.sottotitolo;
          // recisbn.idapp = idapp;

          try {
            let risisbn = await ImportaIsbn.findOneAndUpdate(
              { isbn: productImported.code },
              { $set: recisbn },
              { new: true, upsert: true, strict: false }
            );

            // Update ProductInfo, non crea nuovi record !
            let risrecInfo = await Product.findOneAndUpdate(
              { code: productInfo.code },
              { $set: productInfo },
              { new: true, upsert: false }
            );

            indprod++;
            if (indprod % 100 === 0) console.log(indprod + '/' + numprod);
          } catch (e) {
            console.error(e);
          }
        }
      }

      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.MACRO_CATALOGO_JSON) {
      try {
        const macro = new Macro(idapp, { importadaFDV: true }); // Crea un'istanza della classe Macro
        const result = await macro.importaCatalogo(data); // Chiama il metodo importaCatalogo
        return res.status(200).send(result);
      } catch (e) {
        console.error(e.message);
        return res.status(400).send(e);
      }
    } else if (cmd === shared_consts.Cmd.PRODUCTS) {
      dataObjects = JSON.parse(`[${data.arrdata}]`);

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

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

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

        let reccateg = null;
        if (productImported.cat_name) {
          arrcat = productImported.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 (productImported.subcat_name) {
          arrsubcat = productImported.subcat_name.trim().split(',');
          productInfo.idSubCatProds = [];
          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 (!productImported.hasOwnProperty('active')) {
          productImported.active = true;
        }

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

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

        // Update ProductInfo
        let risrecInfo = await Product.findOneAndUpdate(
          { 'productInfo.code': productInfo.code },
          { $set: { productInfo: productInfo } },
          { new: true, upsert: true }
        );

        if (risrecInfo) {
          productImported.productInfo = risrecInfo._id;

          recnewInfo = await Product.findOne({ code: product.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.productInfo.name + ': ' + arrfieldchange);
            }
          }

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

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

          let recProductExist = null;
          let queryprod = { _id: productImported._id };

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

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

          if (!recProductExist) {
            isnuovo = true;
          }

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

          // AGGIORNA PRODUCT
          let risrec = await Product.findOneAndUpdate(
            queryprod,
            { $set: productImported },
            { 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(productImported, recnew);
              if (arrfieldchange.length > 0) {
                updated++;
                console.log('Changed:', productImported.productInfo.name + ': ' + arrfieldchange);
              }
            } else {
              // Record didn't exist, so it was created
              imported++;
            }
          } else {
            // risrec is null or undefined, indicating an error
            console.error('Error: ', productImported.productInfo.name);
            errors++;
          }

          await Product.singlerecconvert_AfterImport_AndSave(idapp, recnew, isnuovo);
        } else {
          console.error('Error product: ', productImported.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 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) {
              product.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) {
              product.productInfo.idSubCatProds.push(recsubcateg._id);
            }
          }
        }

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

        if (product.productInfo.productTypes.length === 1 && product.productInfo.productTypes[0] === undefined) {
          product.productInfo.productTypes = [shared_consts.PRODUCTTYPE.PRODUCT];
        }

        let esisteindb = await Product.findOne({ 'productInfo.code': product.productInfo.code }).lean();

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

          if (risrecInfo._id) {
            // Record existed, so it was updated
            let arrfieldchange = tools.differentObjects(product.productInfo, recnewInfo.productInfo);
            if (arrfieldchange && arrfieldchange.length > 0) {
              // updated++;
              console.log('Changed: ', recnewInfo.productInfo.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 = { 'productInfo.code': product.productInfo.code };

          //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._id + ': ' + 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.productInfo.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();
});

/*
async function importaCatalogo(data) {
  let updated = 0;
  let imported = 0;
  let errors = 0;

  try {
    const ripopola = true; //++MODIFICARE!

    if (ripopola) {
      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;

          // Ottengo isbn e Pagine da ImportaIsbn

          const recrankingisbn = await ImportaIsbn.findOne({ sku: recmacro.sku }).lean();
          if (recrankingisbn) {
            if (!recmacro.isbn) {
              recmacro.isbn = recrankingisbn.isbn;
            }
            // Se Pagine non sono state settate
            if ((!recmacro.Pagine || recmacro.Pagine === 0) && recrankingisbn.Pagine)
              recmacro.Pagine = recrankingisbn.Pagine;

            // Se misure non sono state settate
            if (!recmacro.misure && recrankingisbn.misure) {
              recmacro.misure = recrankingisbn.misure;
            }
          }

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

          try {
            let risrec = await Importamacro.findOneAndUpdate(
              queryprod,
              { $set: recmacro },
              { new: true, upsert: true, strict: false }
            );
            if (risrec) {
              imported++;
              if (imported % 100 === 0) console.log('Importati su dir Temporanea ', 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;

    let nontrovati = 0;

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

      let importa = true;

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

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

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

        // se non esiste l'ISBN, allora me lo cerco in base a sku !

        let trova = false;
        if (product._id === '30310') {
          trova = true;
        }

        if (!product.isbn || product.isbn.startsWith('field')) {
          const rectrovare = await ImportaIsbn.findOne({ sku: product.sku }).lean();
          if (rectrovare) {
            // se l'isbn non inizia con 'field' allora è buono
            if (rectrovare.isbn && !rectrovare.isbn.startsWith('field')) {
              product.isbn = rectrovare.isbn;
            }
          } else {
            nontrovati++;
            // console.log(`${nontrovati} - ISBN non trovato [sku=${product.sku} title=${product.title}]`)
          }
        }

        let productInfo = {
          idapp: product.idapp,
          code: product.isbn,
          id_wp: product._id,
          sku: product.sku,

          name: product.title,
          description: product.description,
          short_descr: product.short_descr,
          publisher: product.editore,
          collezione: product.Collezione,
          numCollana: product.numCollana,
          // 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 : '',
        };
        const test = false;

        if (test) {
          productInfo.imagefile = '';
          productInfo.image_link = '';
          let { prodInfo, aggiornatoimg } = await downloadImgIfMissing(productInfo);
          console.log('imagefile=', prodInfo.imagefile);
        }

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

        let versione = 0;

        if (indprod % 100 === 0) console.log(indprod + '/' + numprod);

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

        // IdTipologia (Libri (1))
        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);
        }


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

        const recrankingisbn = await ImportaIsbn.findOne({ sku: product.sku }).lean();

        let reccateg = null;

        if (product.categories) {
          // Verifica prima se questa categoria è stata aggiornata !
          if (recrankingisbn && recrankingisbn.DescrArgomento) {
            if (tools.isArray(recrankingisbn.ListaArgomenti) && recrankingisbn.ListaArgomenti.length > 1) {
              console.log('ListaArgomenti STA RITORNANDO UN ARRAY !!!! ', recrankingisbn.ListaArgomenti);
            }

            // !!!!
            for (const idArgomento of recrankingisbn.ListaArgomenti) {
              mycatstr = recrankingisbn.DescrArgomento;

              if (mycatstr) productInfo = await updateProductInfo(productInfo, product, idapp, mycatstr);
            }
          } else {
            arrcat = product.categories.trim().split(',');
            productInfo.idCatProds = [];
            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();
                console.log('CREA con ARGOMENTO VECCHIO... ', mycatstr);
                reccateg = await CatProd.findOne({ idapp, name: mycatstr }).lean();
              }

              if (reccateg) {
                product.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) {}
                }
              }
              product.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) {
                  product.productInfo.idAuthors.push(recauthor._id);
                }
              }
            } catch (e) {
              console.error(e);
            }
          }
        }

        if (product.subcat_name) {
          arrsubcat = product.subcat_name.trim().split(',');
          product.productInfo.idSubCatProds = [];
          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) {
              product.productInfo.idSubCatProds.push(recsubcateg._id);
            }
          }
        }
        if (product.productInfo.publisher) {
          try {
            publisher = product.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) {
              product.productInfo.idPublisher = recpublisher._id;
            }
          } catch (e) {
            console.error(e);
          }
        }
        // Aggiorna la collana solo se non è stata già impostata nel record attuale
        //if (recproductInfoAttuale && !recproductInfoAttuale.idCollana && product.DescrizioneCollana) {
        if (product.productInfo.collezione && product.productInfo.numCollana) {
          reccollana = await Collana.findOne({ idapp, title: collezione }).lean();
          if (!reccollana) {
            try {
              // Non esiste questa collana, quindi la creo !
              reccollana = new Collana({ idapp, idCollana: product.productInfo.numCollana, title: product.DescrizioneCollana });
              ris = await reccoll.save();
            } catch (e) {
              console.error('Err', e);
            }
          }

          if (reccollana) product.productInfo.idCollana = reccollana._id;
        }

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

        // 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;
          }

          // *** CONTROLLA SE AGGIORNARE O MENO DETERMINATI CAMPI CHE SONO STATI GIA' SETTATI
          if (recrankingisbn) {
            if (product.misure !== recrankingisbn.misure && recrankingisbn.misure) {
              product.misure = recrankingisbn.misure;
            }
            if (product.formato !== recrankingisbn.formato && recrankingisbn.formato) {
              product.formato = recrankingisbn.formato;
            }
            if (product.Pagine !== recrankingisbn.Pagine && recrankingisbn.Pagine) {
              product.Pagine = recrankingisbn.Pagine;
            }
            if (product.Edizione !== recrankingisbn.Edizione && recrankingisbn.Edizione) {
              product.Edizione = recrankingisbn.Edizione;
            }
          }

          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.pagine = tools.isValidNumber(product.Pagine) ? tools.convstrToInt(product.Pagine) : 0;
          variazione.misure = product.misure ? product.misure : '';
          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 });
  } catch (e) {
    console.log(e.message);
    return res.status(400).send(e);
  }
}*/

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(server_constants.RIS_CODE_ERR_UNAUTHORIZED).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');

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

    if (!User.isAdmin(req.user.perm) || tokcheck !== TOKCHECK) {
      // If without permissions, exit
      return res.status(server_constants.RIS_CODE_ERR_UNAUTHORIZED).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('/scraper', authenticate, async (req, res) => {
  idapp = req.body.idapp;
  idProduct = req.body.product_id;
  options = req.body.options;

  const scraper = new AmazonBookScraper();

  const product = await Product.getProductById(idProduct);
  let isbn = '';
  if (product) {
    isbn = product.isbn;
  }

  try {
    let data = null;
    if (isbn) {
      data = await scraper.scrapeISBN(product, isbn, options);
      console.log(data);
    }
    return res.send(data);
  } catch (e) {
    console.error(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');

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

    if (!User.isAdmin(req.user.perm) || tokcheck !== TOKCHECK) {
      // If without permissions, exit
      return res.status(server_constants.RIS_CODE_ERR_UNAUTHORIZED).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: '' });
  }
});

router.post('/generate-pdf', async (req, res) => {
  const { url, filename } = req.body;

  if (!url || !filename) {
    return res.status(400).json({ error: 'url e filename sono richiesti' });
  }

  try {
    launchGenPdfIfNeeded(); // Ensure GenPdf is launched before proceeding
    const pdfPath = await genPdf.generatePdfFromUrl(url, filename);
    res.download(pdfPath);
  } catch (error) {
    console.error('Errore generazione PDF:', error);
    res.status(500).json({ error: 'Errore generazione PDF' });
  }
});

module.exports = router;
