const Importamacro = require('../models/importamacro'); // Assicurati di avere i modelli corretti
const ImportaIsbn = require('../models/importaisbn');
const Product = require('../models/product');
const CatProd = require('../models/catprod');
const SubCatProd = require('../models/subcatprod');
const Author = require('../models/author');
const Publisher = require('../models/publisher');
const Collana = require('../models/collana');
const Gasordine = require('../models/gasordine');
const tools = require('../tools/general'); // Assicurati di avere il file delle utility
const shared_consts = require('../tools/shared_nodejs'); // Assicurati di avere le costanti condivise

const Storehouse = require('../models/storehouse');
const ImportaDescr = require('../models/importadescr');
const { getTableContent } = require('../controllers/articleController');

const T_WEB_ArticoliFatturati = require('../models/t_web_articolifatturati');
const T_WEB_Ordini = require('../models/t_web_ordini');
const T_Web_Argomenti = require('../models/t_web_argomenti');
const { JobsInProgress } = require('../models/JobsInProgress');

const fs = require('fs');
const path = require('path');
const csv = require('fast-csv');

// Mappa i campi semplici (senza prefisso 'productInfo.')
const campiProductInfo = [
  'code',
  'descr_trafiletto_catalogo',
  'sottotitolo',
  'descrizione_completa_macro',
  'img2',
  'img3',
  'img4',
  'link',
  'checkout_link',
];

const CSV_PATH = path.resolve(__dirname, '../products.csv');

class Macro {
  constructor(idapp, options) {
    this.idapp = idapp;
    this.localoptions = options;
    this.recProductExist = false;
    this.queryprod = null;
  }

  async updateLocalDbFromGM_T_Web_Articoli(params) {
    console.log('INIZIO updateLocalDbFromGM_T_Web_Articoli...', params);

    let mylog = '';
    let numrec = 0;
    const options = {
      idapp: params.idapp,
      nameTable: 'T_Web_Articoli',
      campispeciali: true,
      recordraw: true,
      query: '',
      showQtaDisponibile: true,
      outhtml: false,
      cmd: shared_consts.CmdQueryMs.GET,
      inputdaGM: true,
      ...params,
    };

    let opt = {
      updated: 0,
      imported: 0,
      errors: 0,
      inputdaGM: options.inputdaGM,
      idapp: options.idapp,
    };

    let myjob = null;

    const lavoromassivo = options.caricatutti;
    if (lavoromassivo) {
      myjob = await JobsInProgress.addNewJob({
        idapp: options.idapp,
        descr: 'Riaggiorna Articoli',
        nomeFunzioneDbOp: 'updateAllBook',
        status: shared_consts.STATUS_JOB.START,
      });
      if (!myjob) {
        mylog = 'ATTENZIONE! ❌ STAVO GIA ESEGUENDO QUESTO JOB, quindi ESCO !';
        console.error(mylog);
        return {
          updated: opt.updated,
          imported: opt.imported,
          errors: opt.errors,
          mylog,
          idRecUpdated: opt.idRecUpdated,
          table: opt.table,
        };
      }
    }

    try {
      let miomatch = {};
      let miomatch2 = {};
      let miolimit = 0;

      if (options.caricatutti) {
        mylog = '*** CaricaTutti ***\n';

        if (options.usaDBGMLocale) {
          mylog += '*** usaDBGMLocale ***\n';
          //miomatch2 = { IdStatoProdotto: { $in: [1, 4, 34, 45, 46] } };

          miomatch2 = {
            $or: [
              { DescrizioneStatoProdotto: 'In commercio' },
              { DescrizioneStatoProdotto: 'Prossima uscita/pubblicazione' },
              { DescrizioneStatoProdotto: 'Prossima uscita' },
              { DescrizioneStatoProdotto: 'In prevendita' },
              { DescrizioneStatoProdotto: 'Vendita sito' },
              { DescrizioneStatoProdotto: '2023 in commercio' },
            ],
            Ean13: { $not: /^USATO/ },
          };

          /*
                    1	In commercio
                    3	Ristampa
                    4	Prossima uscita/pubblicazione
                    6	In promozione
                    7	In fase di valutazione
                    8	Titolo in esaurimento (in attesa Nuova Edizione)
                    9	Titolo in esaurimento
                    20	Titolo in esaurimento (in att N.E Ricopertinata)
                    26	Titolo in Esaurimento (disponibile N.E.)
                    33	In commercio (digitale)
                    34	In prevendita
                    45	Vendita sito
                    46	2023 in commercio
                    47	Assoluto NO Reso
                    48	Titolo esaurito

                    */

          // options.where = { IdStatoProdotto: { $in: [1, 4, 34, 45, 46] } };
        } else {
          options.where = `
                        (DescrizioneStatoProdotto = 'In commercio' OR
                        DescrizioneStatoProdotto = 'Prossima uscita/pubblicazione' OR                        
                        DescrizioneStatoProdotto = 'Prossima uscita' OR
                        DescrizioneStatoProdotto = 'In prevendita' OR
                        DescrizioneStatoProdotto = '2023 in commercio')
                        AND
                        (DescrizioneTipologia = 'Libri' OR
                        DescrizioneTipologia = 'Cartolibro' OR
                        DescrizioneTipologia = 'Carte')
                        AND
                        (Ean13 NOT LIKE 'USATO%')
                        
                        ORDER BY T.IdArticolo DESC, Id DESC
                        `;
        }
      } else {
        miolimit = 1;
        miomatch = {
          IdArticolo: Number(options.sku),
          Ean13: options.isbn,
        };
      }

      let filtroTipologia = null;

      // FILTRO PER LIBRI
      if (true) {
        filtroTipologia = {
          $match: {
            DescrizioneTipologia: { $in: ['Libri', 'Cartolibro', 'Carte'] },
          },
        };
      }

      if (options.usaDBGMLocale) {
        mylog += '*** usaDBGMLocale ***\n';
        options.aggregation = [
          {
            $match: {
              ...miomatch,
            },
          },
          {
            $sort: {
              DataOra: -1,
            },
          },
          {
            $group: {
              _id: '$IdArticolo',
              lastRecord: { $first: '$$ROOT' },
            },
          },
          {
            $replaceRoot: { newRoot: '$lastRecord' },
          },
          {
            $lookup: {
              from: 't_web_statiprodottos',
              localField: 'IdStatoProdotto',
              foreignField: 'IdStatoProdotto',
              as: 'StatoProdotto',
              pipeline: [
                {
                  $sort: { DataOra: -1 },
                },
                {
                  $limit: 1,
                },
              ],
            },
          },
          {
            $addFields: {
              DescrizioneStatoProdotto: { $arrayElemAt: ['$StatoProdotto.Descrizione', 0] },
            },
          },
          {
            $match: {
              ...miomatch2,
            },
          },
          {
            $lookup: {
              from: 't_web_tipologies',
              localField: 'IdTipologia',
              foreignField: 'IdTipologia',
              as: 'DescrizioneTipologia',
              pipeline: [
                {
                  $sort: { DataOra: -1 },
                },
                {
                  $limit: 1,
                },
              ],
            },
          },
          {
            $addFields: {
              DescrizioneTipologia: { $arrayElemAt: ['$DescrizioneTipologia.Descrizione', 0] },
            },
          },
          {
            $match: {
              $expr: {
                $in: ['$DescrizioneTipologia', ['Libri', 'Cartolibro']],
              },
            },
          },
          {
            $lookup: {
              from: 't_web_tipiformatos',
              localField: 'IdTipoFormato',
              foreignField: 'IdTipoFormato',
              as: 'DescrizioneFormato',
            },
          },
          {
            $addFields: {
              DescrizioneFormato: { $arrayElemAt: ['$DescrizioneFormato.Descrizione', 0] },
            },
          },
          ...(filtroTipologia ? [filtroTipologia] : []),
          {
            $lookup: {
              from: 't_web_collanes',
              localField: 'IdCollana',
              foreignField: 'IdCollana',
              as: 'DescrizioneCollana',
            },
          },
          {
            $addFields: {
              DescrizioneCollana: { $arrayElemAt: ['$DescrizioneCollana.Descrizione', 0] },
            },
          },
          {
            $lookup: {
              from: 't_web_edizionis',
              localField: 'IdEdizione',
              foreignField: 'CodEdizione',
              as: 'editore',
            },
          },
          {
            $addFields: {
              editore: { $arrayElemAt: ['$editore.Descrizione', 0] },
            },
          },
          {
            $addFields: {
              ListaAutoriArray: {
                $map: {
                  input: { $split: ['$ListaAutori', ','] },
                  as: 'id',
                  in: {
                    $convert: {
                      input: { $trim: { input: '$$id' } },
                      to: 'int',
                      onError: null,
                      onNull: null,
                    },
                  },
                },
              },
            },
          },
          {
            $lookup: {
              from: 't_web_autoris', // assicurati che il nome della collezione sia corretto
              localField: 'ListaAutoriArray',
              foreignField: 'IdAutore',
              as: 'AutoriDettagliati',
            },
          },
          {
            $addFields: {
              AutoriCompleti: {
                $reduce: {
                  input: '$AutoriDettagliati',
                  initialValue: '',
                  in: {
                    $cond: [
                      { $eq: ['$$value', ''] },
                      { $concat: ['$$this.Nome', ' ', '$$this.Cognome'] },
                      { $concat: ['$$value', ', ', '$$this.Nome', ' ', '$$this.Cognome'] },
                    ],
                  },
                },
              },
            },
          },
          {
            $project: {
              ListaAutoriArray: 0,
              AutoriDettagliati: 0,
            },
          },
          {
            $addFields: {
              ListaArgomentiArray: {
                $map: {
                  input: { $split: ['$ListaArgomenti', ','] },
                  as: 'id',
                  in: { $toInt: { $trim: { input: '$$id' } } },
                },
              },
            },
          },
          // Step: Lookup verso collezione degli argomenti, ordinando per DataOra
          {
            $lookup: {
              from: 't_web_argomentis',
              let: { argomentiArray: '$ListaArgomentiArray' },
              pipeline: [
                {
                  $match: {
                    $expr: {
                      $in: ['$IdArgomento', { $ifNull: ['$$argomentiArray', []] }],
                    },
                  },
                },
                { $sort: { DataOra: -1 } },
                { $limit: 1 },
                { $project: { Descrizione: 1 } },
              ],
              as: 'ArgomentiDettagliati',
            },
          },
          // Step: Genera campo DescrArgomento concatenando tutte le descrizioni
          {
            $addFields: {
              DescrArgomento: {
                $reduce: {
                  input: '$ArgomentiDettagliati',
                  initialValue: '',
                  in: {
                    $cond: [
                      { $eq: ['$$value', ''] },
                      '$$this.Descrizione',
                      { $concat: ['$$value', ', ', '$$this.Descrizione'] },
                    ],
                  },
                },
              },
            },
          },
          {
            $project: {
              ArgomentiDettagliati: 0,
              ListaArgomentiArray: 0,
            },
          },
          {
            $lookup: {
              from: 't_web_disponibiles',
              let: { codice: { $toString: '$IdArticolo' } },
              pipeline: [
                { $match: { $expr: { $eq: ['$Codice', '$$codice'] } } },
                { $sort: { DataOra: -1 } },
                { $limit: 1 },
                { $project: { QtaDisponibile: 1 } },
              ],
              as: 'DisponibileDettaglio',
            },
          },
          {
            $addFields: {
              QtaDisponibile: { $arrayElemAt: ['$DisponibileDettaglio.QtaDisponibile', 0] },
            },
          },
          // Step: Pulisci i campi temporanei
          {
            $project: {
              DisponibileDettaglio: 0,
            },
          },
          {
            $lookup: {
              from: 't_web_marchieditorialis',
              localField: 'IdMarchioEditoriale',
              foreignField: 'IdMarchioEditoriale',
              as: 'CasaEditrice',
            },
          },
          {
            $addFields: {
              CasaEditrice: { $arrayElemAt: ['$CasaEditrice.Descrizione', 0] },
            },
          },
        ];
      } else {
        if (!options.caricatutti) {
          if (options.sku) {
            options.where = 'T.IdArticolo =' + options.sku + " AND T.Ean13 = '" + options.isbn + "'";
          } else {
            options.where = "T.Ean13 = '" + options.isbn + "'";
          }
        }
      }

      let recproducts = await getTableContent(options);

      let idRecUpdated = null;

      if (!tools.isArray(recproducts)) {
        console.error('Error: ', recproducts);
        mylog += recproducts + '\n';
      } else {
        numrec = recproducts?.length || 0;

        console.log('numrec', numrec);
      }

      let rimuoviTabellePerIniziare = false;

      let count = 0;
      if (Array.isArray(recproducts)) {
        if (recproducts.length > 10 && lavoromassivo && options.rimuovieventualiCancellati) {
          //  disattiva dalla tabella product tutti i campi date_updated_fromGM
          const result = await Product.updateMany({ idapp: options.idapp }, { $unset: { date_updated_fromGM: null } });

          let quanti_rimossi = result.  modifiedCount;
          console.log(`Sbianca date_updated_fromGM da Product: (${quanti_rimossi} su ${result.matchedCount})`);
          rimuoviTabellePerIniziare = true;
        }

        if (false) {
          const gruppiPerIsbn = recproducts.reduce((map, product) => {
            const isbn = product.Ean13;
            if (!map.has(isbn)) {
              map.set(isbn, [product]);
            } else {
              map.get(isbn).push(product);
            }
            return map;
          }, new Map());

          const isbnConMultipliRecord = Array.from(gruppiPerIsbn.entries())
            .filter(([isbn, products]) => products.length > 1)
            .map(([isbn]) => isbn);

          recproducts = recproducts.filter((product) => isbnConMultipliRecord.includes(product.Ean13));

          console.log(
            `Trovati ${isbnConMultipliRecord.length} record con ISBN duplicati: ${isbnConMultipliRecord.join(', ')}`
          );
        }

        for (const recproduct of recproducts) {
          await this.elaboraProdotto(recproduct, opt, recproducts.length === 1);

          const sku = recproduct.IdArticolo;

          if (sku) {
            await T_WEB_ArticoliFatturati.updateStatisticsFatt(sku.toString(), options.idapp, true);
            await T_WEB_Ordini.updateStatisticsOrders(sku.toString(), options.idapp, true);
          }
          count++;

          if (count % 50 === 0) {
            const percentuale = Math.round((count / numrec) * 100);
            console.log(
              ` *** RECORD ${count} - IMPORTATI: ${opt.imported} AGGIORNATI = ${opt.updated} (su ${numrec} RECORD) - Completato al ${percentuale}%`
            );
          }
          //}
        }

        if (rimuoviTabellePerIniziare && options.rimuovieventualiCancellati) {
          await Product.unSetDate_Updated_fromGM_OnProduct(options.idapp);
        }
        if (myjob) await myjob.terminateJob();
      }

      if (numrec > 1) {
        opt.idRecUpdated = null;
      }

      if (opt) {
        mylog += ' *** IMPORTATI: ' + opt.imported + ' AGGIORNATI = ' + opt.updated + ' (su ' + numrec + ' RECORD)';
      }

      console.log(mylog);
      return {
        updated: opt.updated,
        imported: opt.imported,
        errors: opt.errors,
        mylog,
        idRecUpdated: opt.idRecUpdated,
        table: opt.table,
      };
    } catch (e) {
      mylog +=
        'ERRORE ! *** IMPORTATI: ' + opt?.imported + ' AGGIORNATI = ' + opt?.updated + ' (su ' + numrec + ' RECORD)';
      opt.logerror = e.message;
      if (myjob) await myjob.terminateJob(true);
      console.error(e.message);
      return { updated: opt.updated, imported: opt.imported, errors: opt.errors, mylog, logerror: opt.logerror };
    }
  }

  /**
   * Funzione principale per importare il catalogo.
   */
  async importaCatalogo(data) {
    let updated = 0,
      imported = 0,
      errors = 0,
      indice = 0;

    try {
      const ripopola = true; //++MODIFICARE!
      if (ripopola) {
        await this.pulisciECaricaDati(data);
      }

      const dataObjects = await Importamacro.find({ idapp: this.idapp }).lean();
      console.log('*** INIZIO IMPORT PRODOTTI ... ');

      for (const product of dataObjects) {
        await this.elaboraProdotto(product, { updated, imported, errors });
        indice++;
      }

      const percentuale = ((indice / dataObjects.length) * 100).toFixed(2);
      console.log(
        `*** RECORD: ${indice} - IMPORTATI: ${imported}, AGGIORNATI = ${updated} (su ${dataObjects.length} RECORD) - Completamento: ${percentuale}%`
      );
      return { updated, imported, errors };
    } catch (e) {
      console.error(e.message);
      throw e;
    }
  }

  /**
   * Pulisce i dati esistenti e carica nuovi dati in Importamacro.
   */
  async pulisciECaricaDati(data) {
    let dataObjects = null;
    try {
      dataObjects = JSON.parse(`[${data.arrdata}]`);
    } catch (e) {
      console.error('Errore nel parsing dei dati:', e);
      return;
    }

    if (dataObjects && dataObjects[0]) {
      await Importamacro.deleteMany({ idapp: this.idapp });

      for (const recinv of dataObjects[0]) {
        const recmacro = this.preparaRecordMacro(recinv);
        const recrankingisbn = await ImportaIsbn.findOne({ sku: recmacro.sku }).lean();

        if (recrankingisbn) {
          this.aggiornaCampiDaIsbn(recmacro, recrankingisbn);
        }

        try {
          await Importamacro.findOneAndUpdate(
            { idapp: this.idapp, _id: recmacro._id },
            { $set: recmacro },
            { new: true, upsert: true, strict: false }
          );
        } catch (e) {
          console.error("Errore durante l'inserimento:", e);
        }
      }
    }
  }

  /**
   * Prepara un record macro per l'inserimento.
   */
  preparaRecordMacro(recinv) {
    const recmacro = { ...recinv };
    recmacro.idapp = this.idapp;
    recmacro._id = recmacro.id;
    delete recmacro.id;
    return recmacro;
  }

  /**
   * Aggiorna i campi del record macro con i dati da ImportaIsbn.
   */
  aggiornaCampiDaIsbn(recmacro, recrankingisbn) {
    if (!recmacro.isbn) recmacro.isbn = recrankingisbn.isbn;
    if ((!recmacro.Pagine || recmacro.Pagine === 0) && recrankingisbn.Pagine) recmacro.Pagine = recrankingisbn.Pagine;
    if (!recmacro.misure && recrankingisbn.misure) recmacro.misure = recrankingisbn.misure;
  }

  /**
   * Elabora un singolo prodotto.
   */
  async elaboraProdotto(productInput, options, forzacaricamento = false) {
    let isnuovo = false,
      setta = false,
      importa = true;

    let product = { ...productInput, deleted: false };

    try {
      if (options.inputdaGM) product = await this.convertiDaCampiGMACampoFDV_ProductInfo(options.idapp, product);

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

      if (importa) {
        if (this.localoptions?.importadaFDV) {
          const recrankingisbn = await ImportaIsbn.findOne({ sku: product.sku }).lean();
          if (recrankingisbn) {
            this.aggiornaCampiDaIsbn(product, recrankingisbn);
          }
        }

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

        //Aggiorna il campo product
        let risprod = await Product.findOneAndUpdate(
          { isbn: product.isbn },
          { $set: product },
          { new: true, upsert: false, returnOriginal: false }
        ).lean();

        const productInfoOriginale = risprod?.productInfo || {};
        const productInfoAggiornata = this.preparaProductInfo(product);
        product.productInfo = { ...productInfoOriginale, ...productInfoAggiornata };
        await this.gestisciCategorie(product);
        await this.gestisciAutori(product);
        await this.gestisciEditore(product);
        await this.gestisciCollana(product);

        // Se non lo trovo allora lo salvo come nuovo.
        const dataFutura = new Date(product.productInfo.date_pub) > new Date(); // è da pubblicare ?
        if (!risprod && (forzacaricamento || product.stockQty > 0 || dataFutura)) {
          await Product.create(product);
          risprod = await Product.findOne({ isbn: product.isbn }).lean();
        } else {
          risprod = await Product.findOne({ isbn: product.isbn }).lean();
        }

        if (risprod) {
          this.queryprod = { _id: risprod._id };

          await this.gestisciGasOrdine(product);
          await this.gestisciVariazioni(product, options);

          const imagefile = await this.aggiornaImmagineSeNecessario(risprod, forzacaricamento || dataFutura);
          if (imagefile) {
            product.productInfo.imagefile = imagefile;
          }

          // aggiorna productInfo
          let risprodInfo = await Product.findOneAndUpdate(
            { isbn: product.isbn },
            { $set: { productInfo: product.productInfo } },
            { new: true, upsert: false, returnOriginal: false }
          ).lean();

          // prodotto risprodInfo trovato ?
          if (risprodInfo) {
            // console.log('Prodotto trovato:', product.productInfo.name, product.productInfo.code);
          }
        } else {
          console.error(
            'Prodotto non trovato:',
            product.productInfo.name,
            product.productInfo.code + 'qta=' + product.stockQty
          );
          options.errors++;
        }
      }
    } catch (e) {
      console.error('Errore nel gestire il prodotto:', e);
      options.errors++;
    }
  }

  async gestisciGasOrdine(product) {
    // 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();
    }

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

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

    if (!this.recProductExist) {
      product.idGasordine = recGas ? recGas._id : null;

      await Product.findOneAndUpdate({ _id: product._id }, { $set: { idGasordine: product.idGasordine } });
    }
  }

  preparaProductInfo(product) {
    try {
      return {
        code: product.isbn,
        id_wp: product._id || undefined,
        sku: product.sku,
        name: product.title,
        description: product.description,
        short_descr: product.short_descr,
        publisher: product.editore,
        collezione: product.collezione,
        idCollana: product.idCollana,
        numCollana: product.numCollana,
        link: product.link || undefined,
        idCatProds: [],
        idSubCatProds: [],
        img2: product.img2 || undefined,
        img3: product.img3 || undefined,
        img4: product.img4 || undefined,
        checkout_link: product.checkout_link || undefined,
        idStatoProdotto: product.idStatoProdotto || undefined,
        date_pub: product.date_pub || undefined,
        sottotitolo: product.sottotitolo || undefined,
        ...(product.date_updated_fromGM ? { date_updated_fromGM: product.date_updated_fromGM } : {}),
        ...(product.link_macro ? { link_macro: product.link_macro } : {}),
        ...(product.descrizione_completa_macro
          ? { descrizione_completa_macro: product.descrizione_completa_macro }
          : {}),
      };
    } catch (e) {
      console.error('Errore preparaProductInfo :', e);
      return {};
    }
  }

  getStatusByIdStatoProdotto(idStatoProdotto) {
    switch (idStatoProdotto) {
      case 1:
      case 4:
      case 34:
      case 45:
      case 46:
        return 'publish';
      default:
        return 'out_of_stock';
    }
  }

  async convertiDaCampiGMACampoFDV_ProductInfo(idapp, productGM) {
    let productFDV = {};

    /* productGM CAMPI
                {
          Id: "257825",
          IdArticolo: 20923,
          Ean13: "9788828508991",
          Titolo: "Fervìda: Fermenti di vita",
          ListaAutori: "3453",
          ListaArgomenti: "12",
          IdStatoProdotto: 46,
          PrezzoIvato: 13.9,
          IdMarchioEditoriale: 1,
          IdCollana: 175,
          DataPubblicazione: "2024-03-26T00:00:00.000Z",
          IdTipologia: 1,
          IdTipoFormato: 1,
          Misure: "cm 17x24",
          Pagine: "80",
          Sottotitolo: "",
          Durata: "",
          Numero: "",
          Edizione: "Marzo 2024",
          Ristampa: "",
          DataInizioCampagna: "2024-12-03T00:00:00.000Z",
          DataFineCampagna: "2099-12-31T00:00:00.000Z",
          ScontoCampagna: 5,
          PrezzoIvatoScontatoCampagna: 13.205,
          DataOra: "2024-12-03T09:56:21.540Z",
          Enabled: false,
          IDTagGruppo: 0,
          Utente: "LENOVO-I5",
          PercIva: 0,
          IdTitoloOriginale: 12272,
          EnabledAlFresco: true,
          CodEdizione: 0,
          FasciaEta: null,
          FasciaEta2: null,
          DescrizioneStatoProdotto: "In commercio",
          DescrizioneTipologia: "Libri",
          DescrizioneFormato: "Brossura",
          DescrizioneCollana: "Il Filo Verde di Arianna",
          AutoriCompleti: "Stefano Abbruzzese",
          DescrArgomento: "Autosufficienza, Autoproduzione e Vita Naturale",
          CasaEditrice: "MACRO EDIZIONI",
        }
        */

    const magazzino_macro = 'Gruppo Macro';

    let recstorehouse = await Storehouse.findOne({ idapp, name: magazzino_macro }).lean();
    if (!recstorehouse) {
      // Non esiste questo produttore, quindi lo creo !
      recstorehouse = new Storehouse({ idapp, name: magazzino_macro });
      ris = await recstorehouse.save();
      recstorehouse = await Storehouse.findOne({ idapp, name: prod.magazzino_name }).lean();
    }

    
    let titolo = productGM.Titolo;

    if (titolo === '') {
      // Controlla se il Titolo esiste nella tabella temporanea, solo se è vuoto quello che mi viene passato.
      const tabdescr = await ImportaDescr.findOne({ code: productGM.Ean13 }).lean();
      if (tabdescr?.title) {
        titolo = tabdescr.title;
      }
    }

    const recproduct = {
      idapp: idapp,
      isbn: productGM.Ean13,
      // id_wp: '',
      sku: productGM.IdArticolo,
      title: titolo, //         productInfo.name.replace(/ - Usato$| - Nuovo$| - Epub$| - Ebook$| - Mobi$| - DVD$| - Streaming$| - Download$/, "");
      description: '',
      short_descr: '',
      collezione: productGM.DescrizioneCollana,
      numCollana: productGM.IdCollana,
      editore: productGM.CasaEditrice,
      Autore: productGM.AutoriCompleti,
      DescrArgomento: productGM.DescrArgomento,
      idStatoProdotto: productGM.IdStatoProdotto,
      Stato: this.getStatusByIdStatoProdotto(productGM.IdStatoProdotto),
      price: productGM.PrezzoIvato,
      sale_price: productGM.PrezzoIvatoScontatoCampagna,
      formato: productGM.DescrizioneFormato,
      Tipologia: productGM.DescrizioneTipologia,
      idTipologia: productGM.IdTipologia,
      idTipoFormato: productGM.IdTipoFormato,
      Pagine: productGM.Pagine,
      misure: productGM.Misure,
      Edizione: productGM.Edizione,
      ristampa: productGM.Ristampa,
      eta: productGM.FasciaEta,
      // addtocart_link: '',
      stockQty: productGM.QtaDisponibile || undefined,
      date_pub: productGM.DataPubblicazione ? tools.getDateFromISOString(productGM.DataPubblicazione) : null,
      productTypes: [shared_consts.PRODUCTTYPE.PRODUCT],
      date_updated_fromGM: new Date(),
      idStorehouses: [recstorehouse._id],
      ...(tabdescr?.descrizione ? { descrizione_breve_macro: tools.getvalueByJsonText(tabdescr?.descrizione) } : {}),
      ...(tabdescr?.descrizione_completa
        ? { descrizione_completa_macro: tools.getvalueByJsonText(tabdescr?.descrizione_completa) }
        : {}),
      ...(tabdescr?.sottotitolo
        ? { sottotitolo: tools.getvalueByJsonText(tabdescr?.sottotitolo) }
        : { sottotitolo: productGM.Sottotitolo }),
      // ...(tabdescr?.titolo ? { name: tools.getvalueByJsonText(tabdescr?.titolo) } : {}),
      ...(tabdescr?.url ? { link_macro: tools.getvalueByJsonText(tabdescr?.url) } : {}),
    };

    let vers = 0;

    if (productGM.DescrizioneTipologia === 'Usato') vers = shared_consts.PRODUCTTYPE.USATO;
    if (productGM.DescrizioneTipologia === 'Download') vers = shared_consts.PRODUCTTYPE.DOWNLOAD;
    else if (productGM.DescrizioneTipologia === 'DVD') vers = shared_consts.PRODUCTTYPE.DVD;
    else if (productGM.DescrizioneTipologia === 'Epub') vers = shared_consts.PRODUCTTYPE.EPUB;
    else if (productGM.DescrizioneTipologia === 'Mobi') vers = shared_consts.PRODUCTTYPE.MOBI;
    else if (productGM.DescrizioneTipologia === 'PDF') vers = shared_consts.PRODUCTTYPE.PDF;
    else if (productGM.DescrizioneTipologia === 'Streaming') vers = shared_consts.PRODUCTTYPE.STREAMING;
    else vers = shared_consts.PRODUCTTYPE.NUOVO;

    recproduct.Versione = vers;

    return recproduct;
  }

  /**
   * Gestisce le categorie e sottocategorie del prodotto.
   */
  async gestisciCategorie(product) {
    try {
      if (product.DescrArgomento) {
        product.productInfo.idCatProds = [];
        const reccateg = await CatProd.findOne({ idapp: this.idapp, name: product.DescrArgomento });
        let nuovaCategoria = null;
        if (!reccateg) {
          nuovaCategoria = new CatProd({ idapp: this.idapp, name: product.DescrArgomento });
          await nuovaCategoria.save();
        }

        if (!reccateg?.idArgomento && product.DescrArgomento) {
          // Se non c'è l'argomento, allora lo cerco nel DB
          const recarg = await T_Web_Argomenti.findOne({ Descrizione: product.DescrArgomento }).lean();
          if (recarg) {
            reccateg.idArgomento = recarg.IdArgomento;
            await reccateg.save();
          }
        }

        const myriscat = reccateg?._id || (nuovaCategoria ? nuovaCategoria._id : null);
        if (myriscat) {
          product.productInfo.idCatProds.push(myriscat);
        }
      } else {
        if (product.categories) {
          // const arrcat = product.categories.trim().split(',');
          const arrcat = product.categories.trim().split(',');
          product.productInfo.idCatProds = [];

          for (const mycat of arrcat) {
            const mycatstr = mycat.trim();
            const reccateg = await CatProd.findOne({ idapp: this.idapp, name: mycatstr }).lean();

            let nuovaCategoria = null;
            if (!reccateg) {
              nuovaCategoria = new CatProd({ idapp: this.idapp, name: mycatstr });
              await nuovaCategoria.save();
            }

            const myriscat = reccateg?._id || (nuovaCategoria ? nuovaCategoria._id : null);
            if (myriscat) {
              product.productInfo.idCatProds.push(myriscat);
            }
          }
        }
      }
    } catch (error) {
      console.error('Errore gestisciCategorie:', error);
    }
  }

  /**
   * Gestisce gli autori del prodotto.
   */
  async gestisciAutori(product) {
    if (product.Autore) {
      let arrAuthor = [];
      if (product.id_wp) arrAuthor = this.estraiAutori_FDV(product.Autore);
      else arrAuthor = this.estraiAutori(product.Autore);

      product.productInfo.idAuthors = [];

      for (const author of arrAuthor) {
        const recauthor = await Author.findOne({
          idapp: this.idapp,
          name: author.name,
          surname: author.surname,
        }).lean();
        let nuovoAutore = null;

        if (!recauthor) {
          nuovoAutore = new Author({ idapp: this.idapp, name: author.name, surname: author.surname });
          await nuovoAutore.save();
        }

        const myrisautore = recauthor?._id || (nuovoAutore ? nuovoAutore._id : '');
        if (myrisautore) product.productInfo.idAuthors.push(myrisautore);
      }
    }
  }

  estraiAutori(autoreString) {
    const arrrecauthor = autoreString.trim().split(',');
    const arrAuthor = [];

    for (let i = 0; i < arrrecauthor.length; i += 2) {
      const nomecognome = arrrecauthor[i].trim();
      let arrrecns = nomecognome.trim().split(' ');
      let name = '';
      let surname = '';

      if (arrrecns && arrrecns.length === 4) {
        name = arrrecns[0].trim() + ' ' + arrrecns[1].trim();
        surname = arrrecns[2].trim() + ' ' + arrrecns[3].trim();
      } else {
        if (arrrecns && arrrecns.length === 1) {
          name = arrrecns[0].trim();
        } else {
          name = arrrecns[0].trim();
          surname = arrrecns.slice(1).join(' ').trim();
        }
      }
      arrAuthor.push({ name, surname });
    }

    return arrAuthor;
  }

  /**
   * Estrae gli autori dal campo "Autore".
   */
  estraiAutori_FDV(autoreString) {
    const arrrecauthor = autoreString.trim().split(',');
    const arrAuthor = [];

    for (let i = 0; i < arrrecauthor.length; i += 2) {
      const name = arrrecauthor[i].trim();
      const surname = arrrecauthor[i + 1]?.trim() || '';
      arrAuthor.push({ name, surname });
    }

    return arrAuthor;
  }

  /**
   * Gestisce l'editore del prodotto.
   */
  async gestisciEditore(product) {
    if (product.productInfo.publisher) {
      const publisher = product.productInfo.publisher.trim();
      const recpublisher = await Publisher.findOne({ idapp: this.idapp, name: publisher }).lean();

      let nuovoEditore = null;
      if (!recpublisher) {
        nuovoEditore = new Publisher({ idapp: this.idapp, name: publisher });
        await nuovoEditore.save();
        if (!nuovoEditore._id) {
          console.error('Errore gestisciEditore: nuovoEditore non ha id');
          return;
        }
      }
      if (recpublisher?._id || nuovoEditore?._id)
        product.productInfo.idPublisher = recpublisher?._id || nuovoEditore._id;
    }
  }

  /**
   * Gestisce la collana del prodotto.
   */
  async gestisciCollana(product) {
    if (product.collezione && product.numCollana) {
      const collana = product.collezione.trim();
      const reccollana = await Collana.findOne({ idapp: this.idapp, title: collana }).lean();

      let nuovaCollana = null;
      if (!reccollana) {
        nuovaCollana = new Collana({ idapp: this.idapp, idCollana: product.numCollana, title: collana });
        await nuovaCollana.save();
        if (!nuovaCollana._id) {
          console.error('Errore gestisciCollana: nuovaCollana non ha id');
          return;
        }
      }
      if (reccollana?._id || nuovaCollana?._id) product.productInfo.idCollana = reccollana?._id || nuovaCollana._id;
    }
  }

  /**
   * Aggiorna l'immagine se necessario.
   */
  async aggiornaImmagineSeNecessario(product, forzacaricamento) {
    const { imagefile, aggiornatoimg } = await tools.downloadImgIfMissing(product, forzacaricamento);
    if (aggiornatoimg) {
      return imagefile;
    }

    return null;
  }

  /**
   * Prepara una variazione del prodotto.
   */
  preparaVariazione(product) {
    return {
      active: true,
      versione: product.Versione,
      status: product.Stato || null,
      price: product.price ? parseFloat(tools.convertPriceEurToValue(product.price)) : null,
      sale_price: product.sale_price ? parseFloat(tools.convertPriceEurToValue(product.sale_price)) : null,
      // formato: product.formato || '',
      idTipologia: product.idTipologia || '',
      idTipoFormato: product.idTipoFormato || '',
      // tipologia: product.Tipologia || '',
      edizione: product.Edizione || '',
      pagine: tools.isValidNumber(product.Pagine) ? tools.convstrToInt(product.Pagine) : 0,
      misure: product.misure || '',
      ristampa: product.ristampa || '',
      eta: product.eta || '',
      addtocart_link: product.addtocart_link || '',
      quantita: product.stockQty ? parseInt(product.stockQty) : 0,
      preOrderDate: product.preOrderDate || null,
    };
  }

  /**
   * Aggiorna l'array delle variazioni.
   */
  aggiornaVariazioni(arrvariazioni, nuovaVariazione) {
    const ind = arrvariazioni.findIndex((x) => x.versione === nuovaVariazione.versione);
    if (ind >= 0) {
      arrvariazioni[ind] = nuovaVariazione;
    } else {
      arrvariazioni.push(nuovaVariazione);
    }
    // rimuovi le variazioni senza versione
    arrvariazioni = arrvariazioni.filter((v) => v.versione);
    return arrvariazioni.sort((a, b) => a.versione - b.versione);
  }
  /**
   * Gestisce le variazioni del prodotto.
   */
  async gestisciVariazioni(product, options) {
    const recold = await Product.findOne(this.queryprod).lean();
    const variazione = this.preparaVariazione(product);

    const myproduct = {
      ...product,
      idapp: this.idapp,
      arrvariazioni: [variazione],
    };

    let risultupdate = null;

    if (recold) {
      let arrvariazioni = this.aggiornaVariazioni(recold.arrvariazioni, variazione);
      const updatedDoc = await Product.findOneAndUpdate(
        this.queryprod,
        { $set: { arrvariazioni } },
        {
          upsert: true,
          new: true, // restituisce il documento aggiornato
          includeResultMetadata: true,
        }
      );
      if (updatedDoc && updatedDoc.lastErrorObject) {
        const wasUpserted = updatedDoc.lastErrorObject.upserted !== undefined;
        const wasUpdated = updatedDoc.lastErrorObject.n === 1 && !wasUpserted;

        if (wasUpserted || wasUpdated) {
          options.updated++;
          options.table = 'products';
          options.idRecUpdated = wasUpserted ? updatedDoc.lastErrorObject.upserted : updatedDoc.value._id;
        }
      }
    }
    if (!recold || this.isModified(recold, myproduct) || !this.recProductExist) {
      const updatedDoc = await Product.findOneAndUpdate(
        this.queryprod,
        { $set: myproduct },
        {
          new: true,
          upsert: true,
          includeResultMetadata: true,
        }
      );
      if (updatedDoc && updatedDoc.lastErrorObject) {
        const wasUpserted = updatedDoc.lastErrorObject.upserted !== undefined;
        const wasUpdated = updatedDoc.lastErrorObject.n === 1 && !wasUpserted;

        if (wasUpserted || wasUpdated) {
          options.imported++;
          options.table = 'products';
          options.idRecUpdated = wasUpserted ? updatedDoc.lastErrorObject.upserted : updatedDoc.value._id;
        }
      }
    }

    // console.log('risultupdate', risultupdate);
  }

  /**
   * Verifica se i campi nella lista sono stati modificati da una versione all'altra.
   * @param {Object} recordOld - record vecchio
   * @param {Object} recordNew - record nuovo
   * @param {string[]} listaCampi - lista dei campi da verificare
   * @returns {boolean} true se i campi sono stati modificati
   */
  isModified(recordOld, recordNew) {
    const listaCampi = [
      'idapp',
      'isbn',
      'price',
      'stockQty',
      //++FIELD_PRODUCT
    ];
    return listaCampi.some((campo) => recordOld[campo] !== recordNew[campo]);
  }

  async getStat() {
    let mystr = '';

    const ris = await Product.countDocuments({
      $or: [{ date_updated_fromGM: { $exists: false } }, { date_updated_fromGM: null }],
    });
    mystr += `${ris} Product non aggiornati da GM, quindi da nascondere ! \n`;

    return mystr;
  }

  async EsportaInfoProductExtra() {
    console.log('EsportaInfoProductExtra...');

    try {
      const products = await Product.find({}, campiProductInfo.map((f) => `productInfo.${f}`).join(' ')).lean();

      const ws = fs.createWriteStream(CSV_PATH);

      let prodExported = 0;

      // Scrivi l'intestazione
      const header = ['code', ...campiProductInfo.slice(1)]; // 'code' è il primo campo
      await new Promise((resolve, reject) => {
        const csvStream = csv.format({ headers: header });
        csvStream.pipe(ws);

        for (const p of products) {
          const row = campiProductInfo.map((field) => p.productInfo?.[field] ?? '');
          const rowToExport = campiProductInfo.slice(1).some((field) => p.productInfo && p.productInfo[field]);
          if (rowToExport) {
            csvStream.write(row);
            prodExported++;
          }
        }
        csvStream.end();
        ws.on('finish', resolve);
        ws.on('error', reject);
      });

      console.log(`Esportazione completata: ${prodExported} su ${products.length} prodotti salvati in ${CSV_PATH}`);
      return prodExported;
    } catch (error) {
      console.error("Errore durante l'esportazione:", error);
      throw error;
    }
  }
  async ImportaInfoProductExtra() {
    console.log('ImportaInfoProductExtra...');

    const records = [];
    try {
      await new Promise((resolve, reject) => {
        const rs = fs.createReadStream(CSV_PATH);
        rs.pipe(csv.parse({ headers: true }))
          .on('error', reject)
          .on('data', (row) => {
            // Costruisci un oggetto productInfo corretto
            const productInfo = {};
            for (const field of campiProductInfo) {
              productInfo[field] = row[field] ?? '';
            }
            records.push({
              code: row.code, // usato per la ricerca
              productInfo,
            });
          })
          .on('end', resolve);
      });

      console.log(`Letti ${records.length} record da ${CSV_PATH}`);

      let aggiornati = 0;
      for (const { code, productInfo } of records) {
        if (!code) continue;

        // Costruisci un oggetto $set con i campi annidati
        const update = {};
        for (const [key, value] of Object.entries(productInfo)) {
          // Salta il campo 'code' perché è usato per la ricerca, non va aggiornato
          if (key === 'code') continue;
          update[`productInfo.${key}`] = value;
        }

        const result = await Product.findOneAndUpdate(
          { 'productInfo.code': code },
          { $set: update },
          { upsert: false, new: true }
        ).lean();

        if (result) aggiornati++;
      }
      
      console.log(`Aggiornati ${aggiornati} prodotti.`);
      return aggiornati;
    } catch (error) {
      console.error("Errore durante l'importazione:", error);
      throw error;
    }
  }
}

module.exports = Macro;
