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

const Hours = require('../models/hours');
const { ObjectId } = require('mongodb');

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

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

const { Settings } = require('../models/settings');
const { MyBot } = require('../models/bot');
const { MyElem } = require('../models/myelem');

const telegrambot = require('../telegram/telegrambot');

const Cart = require('../models/cart');
const CartClass = require('../modules/Cart');
const Product = require('../models/product');
const ProductInfo = require('../models/productInfo');
const CatProd = require('../models/catprod');
const SubCatProd = require('../models/subcatprod');
const Order = require('../models/order');
const OrdersCart = require('../models/orderscart');
const Variant = require('../models/variant');
const TypedError = require('../modules/ErrorHandler');

const { MyGroup } = require('../models/mygroup');
const { Circuit } = require('../models/circuit');
const { Province } = require('../models/province');
const { City } = require('../models/city');
const { Account } = require('../models/account');
const { Catalog } = require('../models/catalog');

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

class CronMod {
  constructor() {}

  async RimuoviInteri(mytable) {
    try {
      console.log('INIZIO - RimuoviInteri ', mytable.modelName);

      const arr = await mytable.find({ _id: { $lte: 10000 } });
      console.log('   search interi...', arr.length);

      const ris = await mytable.deleteMany({ _id: { $lte: 10000 } });

      console.log('FINE - RimuoviInteri ', mytable.modelName, ris);
    } catch (err) {
      console.error(err);
    }
  }

  async eseguiDbOp(idapp, mydata, req, res) {
    let ris = await User.DbOp(idapp, mydata);

    mydata.idapp = idapp;

    const populate = require('../populate/populate');

    const globalTables = require('../tools/globalTables');
    const { Reaction } = require('../models/reaction');

    const AmazonBookScraper = require('../modules/Scraping');

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

    let mystr = '';

    try {
      if (mydata.dbop === '') {
        // } else if (mydata.dbop === 'rigeneraTutto') {
        //   await ListaIngresso.Esegui_CronTab(idapp, mydata);
      } else if (mydata.dbop === 'ScraperMultipleDataAmazon') {
        mystr = await AmazonBookScraper.ScraperMultipleDataAmazon(idapp, {
          update: true,
          aggiornasoloSeVuoti: true,
          forzaricarica: false,
        });
        ris = { mystr };
      } else if (mydata.dbop === 'EsportaInfoProductExtra') {
        const macro = new Macro(idapp, {});
        mystr = await macro.EsportaInfoProductExtra();
        ris = { mystr };
      } else if (mydata.dbop === 'ImportaInfoProductExtra') {
        const macro = new Macro(idapp, {});
        mystr = await macro.ImportaInfoProductExtra();
        ris = { mystr };
      } else if (mydata.dbop === 'ScraperEstraiDatiAmazon-NoUpdate') {
        mystr = await AmazonBookScraper.ScraperMultipleDataAmazon(idapp, {
          update: false,
          aggiornasoloSeVuoti: false,
          forzaricarica: true,
          caricatutti: true,
        });
        ris = { mystr };
      } else if (mydata.dbop === 'ScraperGeneraCSV') {
        mystr = await AmazonBookScraper.ScraperGeneraCSV(idapp, mydata.options, res);
        ris = { mystr };
      } else if (mydata.dbop === 'removeDuplicateVariations') {
        mystr = await AmazonBookScraper.removeDuplicateVariations(idapp, mydata.options);
        ris = { mystr };
      } else if (mydata.dbop === 'ScraperAzzeraFlagProducts') {
        mystr = await AmazonBookScraper.ScraperAzzeraFlagProducts(idapp, mydata.options);
        ris = { mystr };
      } else if (mydata.dbop === 'GeneraPdfCatalogo') {
        const genPdf = new GenPdf(idapp);

        await genPdf.launch();

        return await genPdf.generatePdfFromIdCatalog(mydata.options);
      } else if (mydata.dbop === 'GeneraPdfRaccolta') {
        const genPdf = new GenPdf(idapp);

        await genPdf.launch();

        return await genPdf.generatePdfFromIdRaccolta(mydata.options);
      } else if (mydata.dbop === 'onlinePdfRaccolta') {
        const genPdf = new GenPdf(idapp);

        await genPdf.launch();

        mydata.options.idapp = idapp;

        return await genPdf.onlinePdfFromIdRaccolta(mydata.options);
      } else if (mydata.dbop === 'ReplaceAllCircuits') {
        // ++ Replace All Circuitname with 'Circuito RIS %s'
        await Circuit.replaceAllCircuitNames(idapp);
      } else if (mydata.dbop === 'eliminaCatProds') {
        await CatProd.deleteMany({ idapp });
        await SubCatProd.deleteMany({ idapp });
      } else if (mydata.dbop === 'removeProductInfoWithoutDateUpdatedFromGM') {
        mystr = await Product.removeProductInfoWithoutDateUpdatedFromGM(idapp);
        ris = { mystr };
      } else if (mydata.dbop === 'resetImageNotFound') {
        mystr = await Product.resetImageNotFound();
        ris = { mystr };
      } else if (mydata.dbop === 'StatMacro') {
        const macro = new Macro(idapp, {});
        mystr = await macro.getStat();
        ris = { mystr };
      } else if (mydata.dbop === 'updateAllBook') {
        // chiama updateAllBook
        const { updateAllBook } = require('../controllers/articleController');

        mystr = await updateAllBook(idapp, mydata.options);

        ris = { mystr };
      } else if (mydata.dbop === 'updateAllBooksAndRemoveCanc') {
        // chiama updateAllBooksAndRemoveCanc

        const { updateAllBook } = require('../controllers/articleController');

        console.log('updateAllBooksAndRemoveCanc...');

        mystr = await updateAllBook(idapp, {
          usaDBGMLocale: false,
          caricatutti: true,
          rimuovieventualiCancellati: true,
        });

        ris = { mystr };
      } else if (mydata.dbop === 'creaUtentiTest') {
        let num = 0;
        lastrec = await User.find({ idapp }).sort({ _id: -1 }).limit(1);
        let last = 1;
        if (lastrec) {
          last = lastrec[0].index;
        }
        if (!last) {
          last = 1;
        }

        for (let ind = 0; ind < 100; ind++) {
          let myuser = new User();
          myuser._id = new ObjectId();
          myuser.index = last + ind + 1;
          myuser.idapp = idapp;
          myuser.password = '$2a$12$DEaX1h5saTUVC43f7kubyOAlah1xHDgqQTfSIux0.RFDT9WGbyCaG';
          myuser.lang = 'it';
          myuser.email = 'miaemail@email.it';
          myuser.name = 'U' + myuser.index;
          myuser.surname = 'Ar' + myuser.index;
          myuser.verified_email = true;
          myuser.verified_by_aportador = true;
          if (myuser.index < 2) myuser.perm = '3';
          myuser.username = 'Userna_' + myuser.name;
          myuser.profile.special_req = true;
          myuser.profile.nationality = 'IT';
          await myuser.save();
          num++;
        }

        ris = { num };
      } else if (mydata.dbop === 'CorreggiTabHours') {
        ris = await Hours.correggiHours(idapp);
      } else if (mydata.dbop === 'setVerifiedByAportadorToALL') {
        ris = await User.setVerifiedByAportadorToALL();
      } else if (mydata.dbop === 'RewriteContribType') {
        ris = populate.rewriteTable('contribtypes');
      } else if (mydata.dbop === 'RewriteCategESubCateg') {
        const migration = require('../populate/migration-categories');

        ris = await migration.aggiornaCategorieESottoCategorie();
      } else if (mydata.dbop === 'ReplaceUsername') {
        if (User.isAdmin(req.user.perm)) {
          ris = globalTables.replaceUsername(req.body.idapp, mydata.search_username, mydata.replace_username);
        }
      } else if (mydata.dbop === 'ExitFromAllCircuitWithZero') {
        if (User.isAdmin(req.user.perm)) {
          ris = globalTables.ExitFromAllCircuitWithZero(req.body.idapp, mydata.search_username);
        }
      } else if (mydata.dbop === 'replaceAportadorSolidario') {
        if (User.isAdmin(req.user.perm)) {
          ris = globalTables.replaceAportadorSolidario(req.body.idapp, mydata.search_username, mydata.replace_username);
        }
      } else if (mydata.dbop === 'SearchString') {
        if (User.isAdmin(req.user.perm)) {
          mystr = await globalTables.SearchString(req.body.idapp, mydata.search);
        }
        ris = { mystr };
      } else if (mydata.dbop === 'UpdateCatDeleteEmpty') {
        mystr = await CatProd.updateCatDeleteEmpty(req.body.idapp);
        ris = { mystr };
      } else if (mydata.dbop === 'UpdateStatFatturato') {
        mystr = await Product.updateProductInfoByStats(req.body.idapp);
        ris = { mystr };
      } else if (mydata.dbop === 'MigrateMSSQLToMongoDb') {
        const { mssqlmigrateTables } = require('../controllers/articleController');

        mystr = await mssqlmigrateTables(req);

        ris = { mystr };
      } else if (mydata.dbop === 'copyFrom1To14') {
        const idapporig = 1;
        const idappdest = 14;
        if (!idapporig || !idappdest) return;

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

        //++ Todo: TO FIXIT !
        const mytablesstr = ['settings', 'users', 'templemail', 'destnewsletter', 'contribtypes', 'bots', 'cfgservers'];

        try {
          let numrectot = 0;
          for (const table of mytablesstr) {
            const mytable = globalTables.getTableByTableName(table);

            tools.mylogshow('copyfromapptoapp: ', table, mytable);

            await mytable.DuplicateAllRecords(idapporig, idappdest).then((numrec) => {
              // tools.mylogshow(' REC TO MODIFY: ', rec);
              if (numrec) numrectot += numrec;
            });
          }

          ris = true;
        } catch (e) {
          console.log('e', e);
        }
      } else if (mydata.dbop === 'removeRecordsFav') {
        // Passa le tabelle da users sulle nuove tabelle:
        await User.removerecordsFavorite();
      } else if (mydata.dbop === 'updateReactionsCounts') {
        await Reaction.updateReactionsCounts();
      } else if (mydata.dbop === 'GeneraCSVOrdineProdotti') {
        await Order.GeneraCSVOrdineProdotti();
      } else if (mydata.dbop === 'RemoveDeletedOrdersInOrderscart') {
        await Order.RemoveDeletedOrdersInOrderscart();
      } else if (mydata.dbop === 'CheckTransazioniCircuiti') {
        await Circuit.CheckTransazioniCircuiti(false);
      } else if (mydata.dbop === 'CalcNumTransCircuiti') {
        await Circuit.CheckTransazioniCircuiti(false, { setnumtransaction: true });
      } else if (mydata.dbop === 'CorreggiTransazioniCircuiti') {
        await Circuit.CheckTransazioniCircuiti(true);
      } else if (mydata.dbop === 'RemovePendentTransactions') {
        ris = await SendNotif.RemovePendentTransactions(idapp);
      } else if (mydata.dbop === 'RemoveOldNotif90') {
        await SendNotif.RemoveOldNotif90(idapp);
      } else if (mydata.dbop === 'RemoveOldNotif30') {
        await SendNotif.RemoveOldNotif30(idapp);
      } else if (mydata.dbop === 'UpdateCoordProv') {
        await Province.setCoordinatesOnDB();
      } else if (mydata.dbop === 'insertGeojsonToMongoDB') {
        await City.insertGeojsonToMongoDB('comuni_italia.geojson');
      } else if (mydata.dbop === 'listCollectionsBySize') {
        mystr = await tools.listCollectionsBySize();
        ris = { mystr };
      } else if (mydata.dbop === 'EnableNewsOn_ToAll') {
        mystr = await User.setNewsletterToAll(idapp);
      } else if (mydata.dbop === 'MyElemSetIdPageInsteadThePah') {
        mystr = await MyElem.SetIdPageInsteadThePah(idapp);
        ris = { mystr };
      } else if (mydata.dbop === 'AbilitaNewsletterALL') {
        await User.updateMany(
          {
            $or: [{ deleted: { $exists: false } }, { deleted: { $exists: true, $eq: false } }],
          },
          { $set: { news_on: true } },
          { new: false }
        );
      } else if (mydata.dbop === 'SvuotaTuttiGliAccessiOnlineConToken') {
        await User.SvuotaTuttiGliAccessiOnlineConToken(idapp);
      } else if (mydata.dbop === 'SettaAdTypeOffro_In_Hosps') {
        const { MyHosp } = require('../models/myhosp');

        await MyHosp.SettaAdTypeOffro_In_Hosps(idapp);
      } else if (mydata.dbop === 'removeRegulations') {
        await Circuit.updateMany({}, { $set: { regulation: '' } });
      } else if (mydata.dbop === 'newRecordsFav') {
        // Passa le tabelle da users sulle nuove tabelle:
        await User.moverecordsFavorite(1);
        await User.moverecordsFavorite(2);
        await User.moverecordsFavorite(3);
        await User.moverecordsFavorite(4);
        await User.moverecordsFavorite(5);
      } else if (mydata.dbop === 'emptyTabCatServiziBeni') {
        const { Sector } = require('../models/sector');
        const { SectorGood } = require('../models/sectorgood');
        const { Skill } = require('../models/skill');
        const { Good } = require('../models/good');

        await Sector.deleteMany({});
        await SectorGood.deleteMany({});
        await Skill.deleteMany({});
        ris = await Good.deleteMany({});
      } else if (mydata.dbop === 'emptyDbSkill') {
        // Svuota e Ricrea

        const { Sector } = require('../models/sector');
        const { SectorGood } = require('../models/sectorgood');
        const { Skill } = require('../models/skill');
        const { Good } = require('../models/good');
        const { SubSkill } = require('../models/subskill');
        const { Contribtype } = require('../models/contribtype');
        const { AdType } = require('../models/adtype');
        const { AdTypeGood } = require('../models/adtypegood');
        const { StatusSkill } = require('../models/statusSkill');
        const { CatGrp } = require('../models/catgrp');

        await Sector.deleteMany({});
        await SectorGood.deleteMany({});
        await Skill.deleteMany({});
        await Good.deleteMany({});
        await SubSkill.deleteMany({});
        await Contribtype.deleteMany({});
        await AdType.deleteMany({});
        await AdTypeGood.deleteMany({});
        await StatusSkill.deleteMany({});
        await CatGrp.deleteMany({});

        ris = await populate.popolaTabelleNuove();
      } else if (mydata.dbop === 'ricreaTabCitiesProvinces') {
        // Svuota e Ricrea

        const { City } = require('../models/city');
        const { Province } = require('../models/province');

        await City.deleteMany({});
        await Province.deleteMany({});

        ris = await populate.popolaTabelleNuove();
      } else if (mydata.dbop === 'PopulateTables') {
        ris = populate.popolaTabelleNuove();
      } else if (mydata.dbop === 'dropProducts') {
        if (idapp) {
          const deleteProducts = await Product.deleteMany({ idapp });
          console.log(`Cancellati ${deleteProducts.deletedCount} record dalla collezione Product.`);

          // Cancellazione dei record nella collezione ProductInfo
          const deleteProductInfo = await ProductInfo.deleteMany({ idapp });
          console.log(`Cancellati ${deleteProductInfo.deletedCount} record dalla collezione ProductInfo.`);
        }

        ris = deleteProductInfo ? true : false;
      } else if (mydata.dbop === 'dropCatProd') {
        const deleteCatProd = await CatProd.deleteMany({ idapp });
      } else if (mydata.dbop === 'dropSubCatProd') {
        const deleteSubCatProd = await SubCatProd.deleteMany({ idapp });
      } else if (mydata.dbop === 'dropAllOrders') {
        try {
          const deleteOrder = await Order.deleteMany({ idapp });
          const deleteOrdersCart = await OrdersCart.deleteMany({ idapp });
          const deleteCart = await Cart.deleteMany({ idapp });

          ris = deleteCart;
        } catch (e) {
          console.error('Err:', e);
        }
      } else if (mydata.dbop === 'SistemaGasOrdine') {
        const arrrec = await Product.find({}).lean();
        for (const rec of arrrec) {
          if (tools.isArray(rec.idGasordines) && rec.idGasordines.length > 0) {
            await Product.findByIdAndUpdate(rec._id, { $set: { idGasordine: rec.idGasordines[0] } });
          } else {
            await Product.findByIdAndUpdate(rec._id, { $set: { idGasordine: null } });
          }
        }
      } else if (mydata.dbop === 'CopyPriceToCalc') {
        try {
          const arrrec = await OrdersCart.find({}).lean();
          for (const rec of arrrec) {
            await OrdersCart.findByIdAndUpdate(rec._id, { $set: { totalPriceCalc: rec.totalPrice } });
          }

          const arrrec2 = await Order.find({}).lean();
          for (const rec of arrrec2) {
            await Order.findByIdAndUpdate(rec._id, { $set: { TotalPriceProductCalc: rec.TotalPriceProduct } });
          }
        } catch (e) {
          console.error('Err:', e);
        }
      } else if (mydata.dbop === 'dropAllCarts') {
        ris = await Cart.deleteMany({ idapp });
      } else if (mydata.dbop === 'RewriteCitiesTable') {
        ris = populate.rewriteTable('cities');
      } else if (mydata.dbop === 'RewriteLevelsTable') {
        ris = populate.rewriteTable('levels');
      } else if (mydata.dbop === 'RewriteProvincesTable') {
        ris = populate.rewriteTable('provinces');
      } else if (mydata.dbop === 'emptyCityProvinces') {
        const { City } = require('../models/city');
        const { Province } = require('../models/province');

        await City.deleteMany({});
        await Province.deleteMany({});
      } else if (mydata.dbop === 'ConvTablesFromIntToString') {
        const { MySkill } = require('../models/myskill');
        const { MyBacheca } = require('../models/mybacheca');
        const { MyHosp } = require('../models/myhosp');
        const { MyGood } = require('../models/mygood');
        // const { MyGroup } = require('../models/mygroup');

        console.log('INIZIO - Conversioni');
        // 'myskills',
        // 'mybachecas',
        // 'myhosps',
        // 'mygoods',
        // 'mygroups'

        await ConvertiDaIntAStr(MySkill);
        await ConvertiDaIntAStr(MyBacheca);
        await ConvertiDaIntAStr(MyHosp);
        await ConvertiDaIntAStr(MyGood);
        await ConvertiDaIntAStr(MyGroup);

        console.log('FINE - Conversioni');
      } else if (mydata.dbop === 'RemoveDatiInutiliMySkill') {
        const { MySkill } = require('../models/myskill');

        try {
          const docs = await MySkill.find({}).lean();

          for (const doc of docs) {
            await MySkill.replaceOne({ _id: doc._id }, doc);
          }
          ris = true;
          console.log('RIS', ris);
        } catch (e) {
          console.error('err', e);
        }
      } else if (mydata.dbop === 'Removeinteger') {
        const { MySkill } = require('../models/myskill');
        const { MyBacheca } = require('../models/mybacheca');
        const { MyHosp } = require('../models/myhosp');
        const { MyGood } = require('../models/mygood');
        // const { MyGroup } = require('../models/mygroup');

        console.log('INIZIO - Rimozione');

        await this.RimuoviInteri(MySkill);
        await this.RimuoviInteri(MyBacheca);
        await this.RimuoviInteri(MyHosp);
        await this.RimuoviInteri(MyGood);
        await this.RimuoviInteri(MyGroup);

        console.log('FINE - Rimozione');
      } else if (mydata.dbop === 'createAllCircuits') {
        const { Province } = require('../models/province');

        const arrProv = await Province.find({});
        for (const recprov of arrProv) {
          await Circuit.createCircuitIfNotExist(req, idapp, recprov.prov);
        }
      } else if (mydata.dbop === 'correggiProductTypes') {
        await Product.correggiProductTypes();
      } else if (mydata.dbop === 'replaceProductImgToImageFile') {
        await Product.replaceProductImgToImageFile(true);
      } else if (mydata.dbop === 'removeUploadProducts_Path') {
        await Product.replaceProductImgToImageFile(false);
      } else if (mydata.dbop === 'correggiCircuitiANull') {
        await User.updateMany({}, { $pull: { 'profile.mycircuits': { circuitname: null } } });
      } else if (mydata.dbop === 'ImpostaMinMaxPersonali') {
        await Account.SetMinMaxPersonali(idapp, mydata.valmin, mydata.valmax, '');
      } else if (mydata.dbop === 'ImpostaMinMaxPersonaliCircuito') {
        await Account.SetMinMaxPersonali(idapp, mydata.valmin, mydata.valmax, mydata.circuitId);
      } else if (mydata.dbop === 'ImpostaMinMaxComunitari') {
        await Account.SetMinMaxComunitari(idapp, mydata.valmin, mydata.valmax);
      } else if (mydata.dbop === 'ImpostaMinMaxCollettivi') {
        await Account.SetMinMaxCollettivi(idapp, mydata.valmin, mydata.valmax);
      } else if (mydata.dbop === 'ImpostaDefMinMaxPersonali') {
        await Circuit.SetDefMinMaxPersonali(idapp, mydata.valmin, mydata.valmax, mydata.circuitId);
      } else if (mydata.dbop === 'ImpostaDefMinMaxCollettivi') {
        await Circuit.SetDefMinMaxCollettivi(idapp, mydata.valmin, mydata.valmax, mydata.circuitId);
      } else if (mydata.dbop === 'AbilitaTuttiCircuiti') {
        await Circuit.AbilitaTuttiCircuiti(idapp);
      } else if (mydata.dbop === 'AzzeraRegolamentiTuttiCircuiti') {
        await Circuit.AzzeraRegolamentiTuttiCircuiti(idapp);
      } else if (mydata.dbop === 'setstrProvByIdCityCircuits') {
        await Circuit.setstrProvByIdCityCircuits(idapp);
      } else if (mydata.dbop === 'updateSaldoAndTransato_AllAccounts') {
        await Account.updateSaldoAndTransato_AllAccounts(idapp);
      } else if (mydata.dbop === 'generateBotMenuRecords') {
        await MyBot.generateBotMenuRecords(idapp);
      } else if (mydata.dbop === 'GenerateVapiKey') {
        await tools.generateVapiKey();
      } else if (mydata.dbop === 'convertProductInfos') {
        const products = await Product.find({ idProductInfo: { $exists: true } });
        console.log(
          'eseguiDbOpUser: convertProductInfos - TrovaticonvertProductInfos ',
          products.length,
          ' prodotti con idProductInfo'
        );

        let aggiornati = 0;
        for (const product of products) {
          const productInfo = await ProductInfo.findById(product.idProductInfo);
          if (productInfo) {
            const productInfoObj = productInfo.toObject();
            delete productInfoObj._id;
            delete productInfoObj.__v;
            await Product.updateOne(
              { _id: product._id },
              {
                $set: { productInfo: productInfoObj },
                $unset: { idProductInfo: 1 },
              }
            );

            aggiornati++;

            // ✅ Cancella il record ProductInfo ora che è stato copiato
            await ProductInfo.deleteOne({ _id: productInfo._id });
          }
        }
        console.log('eseguiDbOpUser - Aggiornati ', aggiornati, ' prodotti');
      }

      return ris;
    } catch (e) {
      console.log(e.message);
    }
  }
}

module.exports = CronMod;
