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

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

const Producer = require('../models/producer');
const Storehouse = require('../models/storehouse');
const Provider = require('../models/provider');
const CatProd = require('../models/catprod');
const SubCatProd = require('../models/subcatprod');
const Gasordine = require('../models/gasordine');
const Scontistica = require('../models/scontistica');

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

const { ObjectId } = require('mongodb');

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

// A1P

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

const productSchema = new Schema({
  idapp: {
    type: String,
  },
  deleted: {
    type: Boolean,
  },
  active: {
    type: Boolean,
    default: true,
  },
  isbn: {
    type: String,
  },
  idProductInfo: { type: Schema.Types.ObjectId, ref: 'ProductInfo', index: true }, //@@@ DA CANCELLARE DOPO DELLA CONVERSIONE
  productInfo: {  
    department: {
      type: String, ref: 'Department'
    },
    sku: {
      type: String,
    },
    code: {
      type: String,
      required: true,
    },
    codice: {
      type: String,
    }, // codice interno prodotto
    id_wp: {
      type: String,
    },  // id in wordpress
    codice_EAN: {
      type: String,
    },
    barcode: {
      type: String,
    },
    name: {
      type: String,
      index: true,
    },
    description: {
      type: String,
    },
    short_descr: {
      type: String,
    },
    idCatProds: [{
      type: Schema.Types.ObjectId, ref: 'CatProd', index: true
    }],
    idSubCatProds: [{
      type: Schema.Types.ObjectId, ref: 'SubCatProd'
    }],
    idStatoProdotto: {
      type: Number, index: true
    },
    color: {
      type: String
    },
    size: {
      type: String  // 11x4x3
    },
    weight: {
      type: Number
    },
    weight_lordo: {
      type: Number
    },
    unit: {
      type: Number,
    },
    unit_lordo: {
      type: Number,
    },
    sfuso: {
      type: Boolean
    },  // serve se moltiplicare le qta (es: 12 kg) oppure fare (2 x 20 ml)
    vegan: {
      type: Boolean
    },
    icon: {
      type: String,
    },
    img: {
      type: String,
    },
    imagefile: {
      type: String,
    },
    image_not_found: {
      type: Boolean,
    },
    vers_img: {
      type: Number,
    },
    image_link: {
      type: String,
    },
    link_scheda: {
      type: String,
    },
    link: {
      type: String,
    },
    checkout_link: {
      type: String,
    },
    versioneGM: {
      type: String,
    },
    img2: {
      type: String,
    },
    img3: {
      type: String,
    },
    img4: {
      type: String,
    },
    ingredienti: {
      type: String,
    },
    valori_nutrizionali: {
      type: String,
    },
    note: {
      type: String,
    },
    idAuthors: [{
      type: Schema.Types.ObjectId, ref: 'Author', index: true
    }],
    idCollana: {
      type: Schema.Types.ObjectId, ref: 'Collana', index: true
    },
    idPublisher: {
      type: Schema.Types.ObjectId, ref: 'Publisher', index: true
    },
    collezione: {
      type: String,
    },
    ListaArgomenti: {
      type: String,
    },
    date_pub: {
      type: Date,
      index: 1,
    },
    date_pub_ts: {
      type: Number,
    },
    productTypes: [{
      type: Number,
    }],

    date_updated_fromGM: {
      type: Date,
    },

    totVen: Number,
    totFat: Number,
    vLast3M: Number,
    fatLast3M: Number,
    fatLast6M: Number,
    fatLast1Y: Number,
    fatLast2Y: Number,
    vLast6M: {
      type: Number,
      index: true,
    },
    vLast1Y: {
      type: Number, index: true
    },
    vLast2Y: Number,
    dataUltimoOrdine: Date,
    rank3M: Number,
    rank6M: Number,
    rank1Y: Number,

    descrizione_breve_macro: String,
    descrizione_completa_macro: String,
    descr_trafiletto_catalogo: String,
    sottotitolo: String,
    link_macro: String,
  },
  idProducer: { type: Schema.Types.ObjectId, ref: 'Producer', index: true },
  idStorehouses: [{ type: Schema.Types.ObjectId, ref: 'Storehouse', index: true }],
  idGasordine: { type: Schema.Types.ObjectId, ref: 'Gasordine', index: true },
  idScontisticas: [{ type: Schema.Types.ObjectId, ref: 'Scontistica', index: true }],
  idProvider: { type: Schema.Types.ObjectId, ref: 'Provider', index: true },
  prezzo_ivato: {
    // Con IVA
    type: Number,
  },
  perc_iva: {
    // 4, 10, 22 &
    type: Number,
  },
  price: {
    type: Number,
    required: true,
  },
  arrvariazioni: [
    {
      active: {
        type: Boolean,
      },
      versione: {
        type: Number,
      },
      status: {
        //publish
        type: String,
      },
      price: {
        type: Number,
      },
      sale_price: {
        type: Number,
      },
      quantita: {
        // in magazzino
        type: Number,
      },
      pagine: {
        type: Number,
      },
      misure: {
        type: String,
      },
      edizione: {
        type: String,
      },
      ristampa: {
        type: String,
      },
      formato: {
        type: String,
      },
      tipologia: {
        type: String,
      },
      idTipologia: {
        type: Number,
      },
      idTipoFormato: {
        type: Number,
      },
      edizione: {
        type: String,
      },
      preOrderDate: {
        type: Date,
      },
      addtocart_link: {
        type: String,
      },
      eta: {
        type: String,
      },
    },
  ],
  price_acquistato: {
    type: Number,
  },
  after_price: {
    type: String,
  },
  minBuyQty: {
    // quantità minima acquistabile
    type: Number,
    default: 1,
    required: true,
  },
  minStepQty: {
    // step quantità acquistabile
    type: Number,
    default: 1,
    required: true,
  },
  maxBookableSinglePersQty: {
    // quantità massima Pre-ordinabile (singolarmente)
    type: Number,
    default: 1,
  },
  stockQty: {
    // in magazzino
    type: Number,
    default: 0,
    index: true,
  },
  stockBloccatiQty: {
    // Prenotati Bloccati
    type: Number,
    default: 0,
  },
  bookedQtyOrdered: {
    // Quantità Prenotate ordinate (in Lavorazione)
    type: Number,
  },
  bookedQtyConfirmed: {
    // Quantità Prenotate Confermate Totali
    type: Number,
    default: 0,
  },

  // GAS:
  qtyToReachForGas: {
    // Quantità minima da raggiungere per fare l'ordine GAS
    type: Number,
    default: 0,
  },
  maxbookableGASQty: {
    // Quantità massima (ancora disponibile) Ordine GAS prenotabile (Complessivamente tra tutti gli ordini)
    type: Number,
    default: -1,
  },
  bookedGASQtyOrdered: {
    // Quantità Ordine GAS Prenotate Totali
    type: Number,
    default: 0,
  },
  bookedGASQtyConfirmed: {
    // Quantità Ordine GAS Confermate Totali
    type: Number,
    default: 0,
  },
  bookableGASBloccatiQty: {
    // Quantità Prenotate Bloccate GAS
    type: Number,
  },

  quantityLow: {
    //Soglia disponibilità bassa
    type: Number,
    default: 0,
  },
  visibilityProductOutOfStock: {
    // Visibilità prodotto "esaurito"
    type: Boolean,
  },
  canBeShipped: {
    // è spedibile
    type: Boolean,
  },
  canBeBuyOnline: {
    // è acquistabile online
    type: Boolean,
  },
  stars: {
    type: Number,
  },
  dateAvailableFrom: {
    type: Date,
  },
  note: {
    type: String,
  },
  producer_name: {
    type: String,
  },
  provider_name: {
    type: String,
  },
  magazzino_name: {
    type: String,
  },
  cat_name: {
    type: String,
  },
  subcat_name: {
    type: String,
  },
  sconto1: {
    type: String,
  },
  sconto2: {
    type: String,
  },
  gas_name: {
    type: String,
  },

  date_created: {
    type: Date,
    default: Date.now,
  },
  date_updated: {
    type: Date,
    default: Date.now,
  },
  scraped: {
    type: Boolean,
  },
  scraped_error: {
    type: Boolean,
  },
  scraped_updated: {
    type: Boolean,
  },
  scraped_date: {
    type: Date,
  },
  validaprod: {
    esito: {
      type: Number,
    },
    data: {
      type: Date,
    },
    username: {
      type: String,
    },
    note: {
      type: String,
    },
  },
});

var Product = (module.exports = mongoose.model('Product', productSchema));

productSchema.index({ idapp: 1 });

module.exports.getFieldsForSearch = function () {
  return [
    { field: 'isbn', type: tools.FieldType.string },
    { field: 'productInfo.name', type: tools.FieldType.string },
    { field: 'productInfo.code', type: tools.FieldType.string },
    { field: 'productInfo.description', type: tools.FieldType.string },
  ];
};

module.exports.executeQueryTable = function (idapp, params) {
  params.fieldsearch = this.getFieldsForSearch();
  return tools.executeQueryTable(this, idapp, params);
};

module.exports.executeQueryPickup = async function (idapp, params) {
  let strfindInput = tools.removeAccents(params.search.trim().toLowerCase());

  strfindInput = strfindInput.replace(/#/g, ' '); // aggiungi spazio prima di # se vuoi conservarlo

  // Rimuove le parole "il" e "la" e gli spazi, le @ e i tabulazioni
  // per non farli influire sulla ricerca
  strfindInput = strfindInput
    .replace(/\b(il|la|gli|le|lo|un|una)\b/g, '')
    .replace(/[-@\t]/g, '')
    .trim();

  if (strfindInput === '' && !params.filter) {
    return [];
  }

  let filterfindexact = {};
  if (strfindInput) {
    filterfindexact = { comune: strfindInput };
  }

  let limit = 20;
  let risexact = [];

  const cleanInput = tools.removeAccents(strfindInput.trim());
  const words = cleanInput.split(/\s+/);

  const escapeRegex = (w) => {
    // Escape del carattere '#' e altri caratteri speciali
    return w.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/#/g, '\\#');
  };

  // 🔹 Pattern per productInfo.name: tutte le parole devono essere presenti
  const patternAllWords = words.map((w) => `(?=.*\\b${escapeRegex(w)})`).join('') + '.*';

  let authorConditions = [];

  if (words.length > 0) {
    authorConditions = words.map((word) => {
      const regex = new RegExp(escapeRegex(word), 'i');
      return {
        'productInfo.authors': {
          $elemMatch: {
            $or: [{ name: regex }, { surname: regex }],
          },
        },
      };
    });

    authorConditions = [{ $and: authorConditions }];
  }

  // 🔹 Filtro finale
  const filterfind = {
    idapp,
    $or: [
      {
        'productInfo.name': {
          $regex: patternAllWords,
          $options: 'i',
        },
      },
      {
        'productInfo.code': {
          $regex: `\\b${escapeRegex(cleanInput)}`,
          $options: 'i',
        },
      },
      {
        'productInfo.sku': cleanInput,
      },
      ...authorConditions,
      {
        'productInfo.catprods.name': { $in: words.map(escapeRegex) },
      },
    ],
  };

  if (params.filter) {
    filterfind = { ...params.filter, ...filterfind };
    limit = 200;
  }

  let aggr2 = [
    {
      $lookup: {
        from: 'authors',
        localField: 'productInfo.idAuthors',
        foreignField: '_id',
        as: 'productInfo.authors',
      },
    },
    {
      $unwind: {
        path: '$authors',
        preserveNullAndEmptyArrays: true,
      },
    },
    {
      $lookup: {
        from: 'catprods',
        localField: 'productInfo.idCatProds',
        foreignField: '_id',
        as: 'productInfo.catprods',
      },
    },
    {
      $unwind: {
        path: '$productInfo.catprods',
        preserveNullAndEmptyArrays: true,
      },
    },
    {
      $match: filterfind,
    },
    { $limit: limit },
    {
      $project: {
        name: '$productInfo.name', // Nome del prodotto
        authors: '$productInfo.authors',
        productInfo: {
          name: '$productInfo.name', // Nome dell'autore
          authors: '$productInfo.authors',
          idStatoProdotto: '$productInfo.idStatoProdotto',
          date_pub: '$productInfo.date_pub',
          catprods: '$productInfo.catprods',
        },
        arrvariazioni: '$arrvariazioni',
      },
    },
    {
      $sort: {
        'productInfo.date_pub': -1,
        'productInfo.name': 1, // Ordina per name in ordine crescente
      },
    },
  ];

  let ris = await this.aggregate(aggr2).limit(limit);

  return [...risexact, ...ris];
};

module.exports.getProductByIsbn = function (idapp, isbn) {
  return Product.findAllIdApp(idapp, null, null, null, isbn);
};
module.exports.getProductByCode = function (idapp, code) {
  return Product.findAllIdApp(idapp, code);
};

module.exports.getProductById = async function (id) {
  const arrris = await Product.findAllIdApp('', '', id);
  return arrris && arrris.length > 0 ? arrris[0] : null;
};

module.exports.getInStockById = async function (id) {
  const myprod = await Product.findOne({ _id: id });
  if (myprod) {
    let instock = 0;
    if (myprod.idGasordine) {
      instock = myprod.maxbookableGASQty;
    } else {
      instock = myprod.stockQty;
    }
    return instock;
  }
  return null;
};

module.exports.isLowQuantityInStockById = async function (id) {
  const instock = await Product.getInStockById(id);
  const myprod = await Product.findOne({ _id: id });
  if (instock) {
    return instock <= myprod.quantityLow + 1;
  }
  return false;
};

module.exports.findAllIdApp = async function (idapp, code, id, all, isbn) {
  let myfind = {};
  let myqueryadd = {};
  let query = [];

  try {
    if (id === 'undefined') {
      return [];
    }

    if (idapp) {
      myfind = {
        idapp,
        $or: [{ deleted: { $exists: false } }, { deleted: { $exists: true, $eq: false } }],
      };
    }

    if (!all) {
      myfind = { ...myfind, active: true };
    }

    if (code) {
      myfind = { ...myfind, code };
    }
    if (isbn) {
      myfind = { ...myfind, isbn };
    }
    if (id) {
      myqueryadd = {
        $addFields: {
          myId1: {
            $toObjectId: id,
          },
        },
      };
      myfind = {
        $expr: {
          $eq: ['$_id', '$myId1'],
        },
      };

      query.push(myqueryadd);
    }

    // DA TOGLIEREE
    // myfind = { ...myfind, code: '4012824406094' };

    // return await Product.find(myfind);

    query.push(
      // PRIMO FILTRO: riduce subito il numero di documenti
      { $match: myfind },

      // UNICO LOOKUP ORDERS CON FACET PER RIDURRE I DOPPIONI
      {
        $lookup: {
          from: 'orders',
          let: { productId: '$_id' },
          pipeline: [
            {
              $match: {
                $expr: {
                  $and: [
                    { $eq: ['$idProduct', '$$productId'] },
                    {
                      $or: [
                        { $eq: ['$status', shared_consts.OrderStatus.CHECKOUT_SENT] },
                        {
                          $and: [
                            { $lt: ['$status', shared_consts.OrderStatus.CHECKOUT_SENT] },
                            {
                              $gt: ['$modify_at', { $subtract: [new Date(), 60 * 60 * 1000] }],
                            },
                          ],
                        },
                      ],
                    },
                  ],
                },
              },
            },
            {
              $group: {
                _id: null,
                totalQty: { $sum: '$quantity' },
                totalQtyPreordered: { $sum: '$quantitypreordered' },
              },
            },
          ],
          as: 'orderSummary',
        },
      },

      // ESTRAGGO LE QUANTITÀ IN CAMPI AGGIUNTIVI
      {
        $addFields: {
          QuantitaOrdinateInAttesa: {
            $ifNull: [{ $arrayElemAt: ['$orderSummary.totalQty', 0] }, 0],
          },
          QuantitaPrenotateInAttesa: {
            $ifNull: [{ $arrayElemAt: ['$orderSummary.totalQtyPreordered', 0] }, 0],
          },
        },
      },

      // CALCOLO DELLE DISPONIBILITÀ
      {
        $addFields: {
          quantityAvailable: {
            $subtract: ['$stockQty', '$QuantitaOrdinateInAttesa'],
          },
          bookableAvailableQty: {
            $subtract: ['$maxbookableGASQty', '$QuantitaPrenotateInAttesa'],
          },
        },
      },

      // ELIMINO IL RISULTATO TEMPORANEO
      { $unset: 'orderSummary' },

      // LOOKUP MULTIPLI MA ORGANIZZATI
      {
        $lookup: {
          from: 'producers',
          localField: 'idProducer',
          foreignField: '_id',
          as: 'producer',
        },
      },
      { $unwind: { path: '$producer', preserveNullAndEmptyArrays: true } },

      {
        $match: {
          'productInfo.code': { $exists: true, $ne: '' },
          //'productInfo.imagefile': { $ne: 'noimg.jpg' },
        },
      },
      {
        $lookup: {
          from: 'gasordines',
          localField: 'idGasordine',
          foreignField: '_id',
          as: 'gasordine',
        },
      },
      { $unwind: { path: '$gasordine', preserveNullAndEmptyArrays: true } },

      // FILTRO DOPO LOOKUP SU GASORDINE
      {
        $match: {
          $or: [{ 'gasordine.active': true }, { gasordine: { $exists: false } }],
        },
      },

      // LOOKUP SU AUTHORS
      {
        $lookup: {
          from: 'authors',
          localField: 'productInfo.idAuthors',
          foreignField: '_id',
          as: 'productInfo.authors',
        },
      },

      // LOOKUP PUBBLICATORI, COLLANE, CATEGORIE, ECC.
      {
        $lookup: {
          from: 'publishers',
          localField: 'productInfo.idPublisher',
          foreignField: '_id',
          as: 'productInfo.publisher',
        },
      },
      { $unwind: { path: '$productInfo.publisher', preserveNullAndEmptyArrays: true } },

      {
        $lookup: {
          from: 'collanas',
          localField: 'productInfo.idCollana',
          foreignField: '_id',
          as: 'productInfo.collana',
        },
      },
      { $unwind: { path: '$productInfo.collana', preserveNullAndEmptyArrays: true } },

      {
        $lookup: {
          from: 'catprods',
          localField: 'productInfo.idCatProds',
          foreignField: '_id',
          as: 'productInfo.catprods',
        },
      },
      {
        $lookup: {
          from: 'subcatprods',
          localField: 'productInfo.idSubCatProds',
          foreignField: '_id',
          as: 'productInfo.subcatprods',
        },
      },
      {
        $lookup: {
          from: 'scontisticas',
          localField: 'idScontisticas',
          foreignField: '_id',
          as: 'scontisticas',
        },
      },
      {
        $lookup: {
          from: 'storehouses',
          localField: 'idStorehouses',
          foreignField: '_id',
          as: 'storehouses',
        },
      },
      {
        $lookup: {
          from: 'providers',
          localField: 'idProvider',
          foreignField: '_id',
          as: 'provider',
        },
      },
      { $unwind: { path: '$provider', preserveNullAndEmptyArrays: true } },

      // ORDINAMENTO FINALE
      {
        $sort: {
          'productInfo.name': 1,
        },
      }
    );

    // console.log('query=', query);

    let ris = await Product.aggregate(query);

    // console.table('ris', ris);

    return ris;
  } catch (e) {
    console.error('E', e);
    return [];
  }
};

module.exports.getAllProducts = function (query, sort, callback) {
  Product.find(query, null, sort, callback);
};

module.exports.getProductByDepartment = function (query, sort, callback) {
  Product.find(query, null, sort, callback);
};

module.exports.getProductByCatProd = function (query, sort, callback) {
  Product.find(query, null, sort, callback);
};

module.exports.getProductByTitle = function (query, sort, callback) {
  Product.find(query, null, sort, callback);
};

module.exports.filterProductByDepartment = function (department, callback) {
  let regexp = new RegExp(`^${department}$`, 'i');
  var query = { department: { $regex: regexp } };
  Product.find(query, callback);
};

module.exports.filterProductByCatProd = function (catprod, callback) {
  let regexp = new RegExp(`^${catprod}$`, 'i');
  var query = { catprod: { $regex: regexp } };
  Product.find(query, callback);
};

module.exports.filterProductByTitle = function (title, callback) {
  let regexp = new RegExp(`^${title}$`, 'i');
  var query = { title: { $regex: regexp } };
  Product.find(query, callback);
};

module.exports.getProductByID = function (id, callback) {
  Product.findById(id, callback);
};

module.exports.updateProductInOrder = async function (order) {
  if (order.product) order.product = await Product.getProductById(order.product._id);

  return order;
};

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

module.exports.convertAfterImportALLPROD = async function (idapp, dataObjects) {
  const arrprod = await Product.find({ idapp }).lean();
  for (const prod of arrprod) {
    await this.singlerecconvert_AfterImport_AndSave(prod);
  }
};

module.exports.getArrCatProds = async function (idapp, cosa) {
  try {
    let addquery = [];
    let arr = [];
    if (cosa === shared_consts.PROD.GAS) {
      addquery = [{ $match: { idapp, idGasordine: { $exists: true, $ne: null, $type: 'objectId' } } }];

      addquery.push({
        $lookup: {
          from: 'gasordines',
          localField: 'idGasordine',
          foreignField: '_id',
          as: 'gasordine',
        },
      });

      addquery.push({
        $match: {
          'gasordine.active': true,
        },
      });
    } else if (cosa === shared_consts.PROD.BOTTEGA) {
      addquery = [
        {
          $match: {
            idapp,
            $or: [{ idGasordine: { $exists: false } }, { idGasordine: { $exists: true, $eq: null } }],
          },
        },
      ];
    } else {
      addquery = [{ $match: { idapp } }];
    }

    let myquery = [
      ...addquery,
      {
        $lookup: {
          from: 'catprods',
          localField: 'productInfo.idCatProds',
          foreignField: '_id',
          as: 'category',
        },
      },
      { $unwind: '$category' },
      {
        $group: {
          _id: '$category._id',
          name: { $first: '$category.name' },
          idapp: { $first: '$category.idapp' },
          idArgomento: { $first: '$category.idArgomento' },
        },
      },
      {
        $match: {
          $or: [{ idapp: { $ne: tools.MACRO } }, { idapp: tools.MACRO, idArgomento: { $exists: true, $gt: 0 } }],
        },
      },

      { $sort: { name: 1 } },
    ];

    try {
      let arr = [];
      arr = await Product.aggregate(myquery);

      if (cosa !== shared_consts.PROD.GAS) {
        // console.log(JSON.stringify(myquery, null, 2))
      }

      // arr = result.map(category => category.name);
      return arr;
    } catch (e) {
      console.error('err', e);
    }
    // Ora uniqueCategories contiene l'array delle categorie univoche utilizzate in tutti i prodotti con active = true
    return arr;
  } catch (e) {
    console.error('err', e);
    return [];
  }
};

module.exports.singlerecconvert_AfterImport_AndSave = async function (idapp, prod, isnuovo) {
  let setta = false;

  try {
    let objtoset = {};
    let rec = null;

    // Impostazioni Base:
    if (isnuovo) {
      objtoset = {
        idapp,
        // minBuyQty: 1,
        // minStepQty: 1,
        maxBookableSinglePersQty: 0,
        bookedGASQtyOrdered: 0,
        bookableGASBloccatiQty: 0,
        bookedGASQtyConfirmed: 0,
        // qtyToReachForGas: 0,
        // maxbookableGASQty: 0,
      };
    }

    if (prod.producer_name) {
      // Cerca il produttore
      let recproducer = await Producer.findOne({ idapp, name: prod.producer_name }).lean();
      if (!recproducer) {
        // Non esiste questo produttore, quindi lo creo !
        recproducer = new Producer({ idapp, name: prod.producer_name });
        ris = await recproducer.save();
        recproducer = await Producer.findOne({ idapp, name: prod.producer_name }).lean();
      }

      if (recproducer) {
        objtoset = {
          ...objtoset,
          idProducer: recproducer._id,
        };
        setta = true;
      }
    }

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

      if (recstorehouse) {
        objtoset = {
          ...objtoset,
          idStorehouses: [recstorehouse._id],
        };
        setta = true;
      }
    }

    if (prod.provider_name) {
      // Cerca il produttore
      let recprovider = await Provider.findOne({ idapp, name: prod.provider_name }).lean();
      if (!recprovider) {
        recprovider = new Provider({ idapp, name: prod.provider_name });
        // Non esiste questo produttore, quindi lo creo !
        ris = await recprovider.save();
        recprovider = await Provider.findOne({ idapp, name: prod.provider_name }).lean();
      }

      if (recprovider) {
        objtoset = {
          ...objtoset,
          idProvider: recprovider._id,
        };
        setta = true;
      }
    }
    if (prod.gas_name) {
      // Cerca il GAS
      rec = await Gasordine.findOne({ idapp, name: prod.gas_name }).lean();
      if (!rec) {
        rec = new Gasordine({ idapp, name: prod.gas_name, active: true });
        // Non esiste questo GAS, quindi lo creo !
        ris = await rec.save();
        rec = await Gasordine.findOne({ idapp, name: prod.gas_name }).lean();
      }

      if (rec) {
        objtoset = {
          ...objtoset,
          idGasordine: rec._id,
        };
        setta = true;
      }
    }

    let arrsconti = [];

    if (prod.sconto1) {
      // Cerca la scontistica
      let recscontistica = await Scontistica.findOne({ idapp, code: prod.sconto1 }).lean();
      if (!recscontistica) {
        recscontistica = new Scontistica({ idapp, code: prod.sconto1 });
        // Non esiste questa scontistica, quindi lo creo !
        ris = await recscontistica.save();
        recscontistica = await Scontistica.findOne({ idapp, code: prod.sconto1 }).lean();
      }

      if (recscontistica) {
        arrsconti.push(recscontistica);
      }
    }

    if (prod.sconto2) {
      // Cerca la scontistica
      let recscontistica = await Scontistica.findOne({ idapp, code: prod.sconto2 }).lean();
      if (!recscontistica) {
        recscontistica = new Scontistica({ idapp, code: prod.sconto2 });
        // Non esiste questa scontistica, quindi lo creo !
        ris = await recscontistica.save();
        recscontistica = await Scontistica.findOne({ idapp, code: prod.sconto2 }).lean();
      }

      if (recscontistica) {
        arrsconti.push(recscontistica);
      }
    }

    if (arrsconti.length > 0) {
      objtoset = {
        ...objtoset,
        idScontisticas: arrsconti,
      };
      setta = true;
    }

    // Aggiorna il prezzo ?
    const aggiornaprezzo = false;
    if (aggiornaprezzo) {
      // cerca il prodotto
      const myprodinput = dataObjects.find((rec) => rec._id === prod._id);
      if (myprodinput) {
        objtoset = {
          ...objtoset,
          price: myprodinput.price,
        };
      }
    }

    if (!tools.isObjectEmpty(objtoset)) {
      ris = await Product.findOneAndUpdate({ _id: prod._id }, { $set: objtoset });

      const objDelete = {
        cat_name: 1,
        subcat_name: 1,
        producer_name: 1,
        provider_name: 1,
        magazzino_name: 1,
        sconto1: 1,
        sconto2: 1,
        gas_name: 1,
      };

      ris = await Product.updateOne({ _id: prod._id }, { $unset: objDelete });

      if (ris && ris.modifiedCount > 0) {
        console.log('Modificato: ', objtoset.name);
      }

      // const campodarimuovere = 'producer_name';
      // await Product.findOneAndUpdate({ _id: prod._id }, { $unset: { [campodarimuovere]: 1 } })
    }
  } catch (e) {
    console.error('Err', e);
  }
};

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

module.exports.replaceProductImgToImageFile = async function (abilitaserver) {
  const Product = this;

  if (abilitaserver) {
    // const result = await ProductInfo.updateMany({ "img": { $exists: true } }, { $rename: { 'img': 'imagefile' } });

    // Trova tutti i documenti con il campo 'img' che esiste
    const documents = await Product.find({ "productInfo.img": { $exists: true } });

    // Aggiorna ciascun documento
    for (let doc of documents) {
      if (doc.img && doc.img.startsWith('upload/products/')) {
        // Rimuovi il prefisso '/upload/products' dal campo `img`
        doc.imagefile = doc.img.replace(/^\upload\/products\//, '');
        doc.img = undefined; // Può anche rimuovere il campo img corrente se desiderato
        await doc.save(); // Salva il documento aggiornato
      }
    }

    console.log(`Updated ${documents.length} document(s) with new imagefile paths.`);

  } else {
    const documents = await Product.find({ "productInfo.imagefile": { $exists: true } });

    // Aggiorna ciascun documento
    for (let doc of documents) {
      if (doc.imagefile && doc.imagefile.startsWith('upload/products/')) {
        // Rimuovi il prefisso '/upload/products' dal campo `img`
        doc.imagefile = doc.imagefile.replace(/^\upload\/products\//, '');
        await doc.save(); // Salva il documento aggiornato
      }
    }

    console.log(`Updated ${documents.length} document(s) with new imagefile paths.`);


  }


  // await Product.updateMany({}, { 'vers_img': 0 });

  console.log(`Updated ${result.modifiedCount} document(s).`);

};



module.exports.correggiProductTypes = async function () {
  const Product = this;
  const bulkOps = [];

  try {
    // Fase di aggregazione
    const cursor = Product.aggregate([
      {
        $project: {
          _id: 1,
          'productInfo.productType': 1,
          'productInfo.productTypes': [{ $ifNull: ['$productType', 10] }]
        }
      }
    ]).cursor({ batchSize: 1000 }).exec();

    // Itera attraverso ogni documento utilizzando il cursore
    for await (const doc of cursor) {
      bulkOps.push({
        updateOne: {
          filter: { _id: doc._id },
          update: {
            $set: { 'productInfo.productTypes': doc.productTypes },
            $unset: { 'productInfo.productType': "" }
          }
        }
      });

      // Scrivi i batch di operazioni ogni 1000 documenti
      if (bulkOps.length === 1000) {
        await Product.bulkWrite(bulkOps);
        bulkOps.length = 0;
      }
    }

    // Scrivi eventuali operazioni rimanenti
    if (bulkOps.length > 0) {
      await Produc.bulkWrite(bulkOps);
    }

    console.log('ProductInfo.productType converted to productTypes array and saved');
  } catch (err) {
    console.error('Error converting ProductInfo.productType:', err);
  }
}

module.exports.updateProductInfoByStats = async function (idapp) {
  let mylog = '';
  let mylog2 = '';
  let mylogtot = '';
  try {
    const Product = this;

    const T_WEB_ArticoliFatturati = require('./t_web_articolifatturati');
    const T_WEB_Ordini = require('./t_web_ordini');

    mylog = "Inizio Aggiornamento Statistiche... \n";
    mylogtot += mylog;
    console.log(mylog);

    let countUpdate = 0;

    countUpdate = await T_WEB_ArticoliFatturati.updateStatisticsFatt('', idapp, true);
    
    // Itera sui risultati e aggiorna productInfo

    mylog = `Aggiornati ${countUpdate} record di productInfo`;
    mylogtot += mylog;
    console.log(mylog);

    mylog2 = "Inizio Aggiornamento Statistiche Ordini ... \n";
    mylogtot += mylog2;
    console.log(mylog2);

    countUpdate = await T_WEB_Ordini.updateStatisticsOrders('', idapp, true);

    mylog2 = `Aggiornati ${countUpdate} record di productInfo`;
    mylogtot += mylog2;

    console.log(mylog2);

  } catch (error) {
    mylog = "Errore durante l'aggiornamento di productInfo:" + error;
    console.error(mylog);
  }

  return mylogtot;
}

// crea setImgNotFound 

module.exports.setImgNotFound = async function (id) {
  // set sul record id il flag image_not_found
  try {
    const Product = this;
    
    await Product.updateOne(
      { _id: id },
      { $set: { 'productInfo.image_not_found': true } }
    );
    console.log(`Flag image_not_found set for record with id: ${id}`);
  } catch (error) {
    console.error(`Error setting image_not_found flag for id ${id}:`, error);
  }

}

// imposta tutti i record con image_not_found: false
module.exports.resetImageNotFound = async function () {
  try {
    const Product = this;
    
    await Product.updateMany(
      { 'productInfo.image_not_found': true },
      { $set: { image_not_found: false } }
    );
    console.log('Flag image_not_found reset to false for all records');
    return true;
  } catch (error) {
    console.error('Error resetting image_not_found flag:', error);
  }

}

// crea una funzione che mi rimuove il record "product" che utilizza productInfo, nel caso in cui date_updated_fromGM non esista
module.exports.removeProductInfoWithoutDateUpdatedFromGM = async function (idapp) {
  const Product = this;
  
  let mylog;

  try {
    const arrproduct = await Product.find({ idapp, 'productInfo.date_updated_fromGM': { $exists: false } });

    if (arrproduct.length > 0 && arrproduct.length < 1000) {
      mylog = `Rimuovo ${arrproduct.length} product senza date_updated_fromGM !!`
      console.log(mylog);

      for (const product of arrproduct) {
        await Product.updateOne(
          { _id: product._id },
          { $set: { deleted: true } }
        );
      }
    }

    return mylog;
  } catch (error) {
    mylog += 'Error removing productInfo without date_updated_fromGM:' + error;
    console.error(mylog);
  }

  return mylog;
};
module.exports.unSetDate_Updated_fromGM_OnProduct = async function (idapp) {
  const Product = this;
  
  let mylog;

  try {
    const arrproduct = await Product.find({ idapp, 'productInfo.date_updated_fromGM': { $exists: false } });

    if (arrproduct.length > 0 && arrproduct.length < 1000) {
      mylog = `Nascondo ${arrproduct.length} product senza date_updated_fromGM !!`
      console.log(mylog);

      for (const product of arrproduct) {
        await Product.updateOne(
          { _id: product._id },
          { $unset: { date_updated_fromGM: true } }
        );
      }
    }

    return mylog;
  } catch (error) {
    mylog += 'Error Hide productInfo without date_updated_fromGM:' + error;
    console.error(mylog);
  }

  return mylog;
};
