const os = require('os');

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

const path = require('path');

require('../config/config');

require('../models/subscribers');

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

const mongoose = require('mongoose');

const { User } = require('../models/user');
const { MyGroup } = require('../models/mygroup');
const { Booking } = require('../models/booking');
const { Operator } = require('../models/operator');
const { Where } = require('../models/where');
const { MyEvent } = require('../models/myevent');
const { Reaction } = require('../models/reaction');
const { Contribtype } = require('../models/contribtype');
const { PaymentType } = require('../models/paymenttype');
const { Discipline } = require('../models/discipline');
const { Skill } = require('../models/skill');
const { Catalog } = require('../models/catalog');
const { RaccoltaCataloghi } = require('../models/raccoltacataloghi');
const { Good } = require('../models/good');
const { Bacheca } = require('../models/bacheca');
const { SubSkill } = require('../models/subskill');
const { MySkill } = require('../models/myskill');
const { Attivita } = require('../models/attivita');
const { MyGood } = require('../models/mygood');
const { MyBacheca } = require('../models/mybacheca');
const { MyHosp } = require('../models/myhosp');
const { StatusSkill } = require('../models/statusSkill');
const { City } = require('../models/city');
const { Province } = require('../models/province');
const { Sector } = require('../models/sector');
const { SectorGood } = require('../models/sectorgood');
const { CatGrp } = require('../models/catgrp');
const { Level } = require('../models/level');
const { AdType } = require('../models/adtype');
const { AdTypeGood } = require('../models/adtypegood');
const { Circuit } = require('../models/circuit');
const { Account } = require('../models/account');
const { Movement } = require('../models/movement');
const Pickup = require('../models/pickup');
const { Newstosent } = require('../models/newstosent');
const { MyPage } = require('../models/mypage');
const { MyElem } = require('../models/myelem');
const { MyScrapingBook } = require('../models/myscrapingbook');
const { Cron } = require('../models/cron');
const { MyScheda } = require('../models/myscheda');
const { MyBot } = require('../models/bot');
const { CfgServer } = require('../models/cfgserver');
const { CalZoom } = require('../models/calzoom');
const { Gallery } = require('../models/gallery');
const { TemplEmail } = require('../models/templemail');
const { DestNewsletter } = require('../models/destnewsletter');
const { OpzEmail } = require('../models/opzemail');
const { MailingList } = require('../models/mailinglist');
const { Settings } = require('../models/settings');
const { SendMsg } = require('../models/sendmsg');
const { Permission } = require('../models/permission');
const { MsgTemplate } = require('../models/msg_template');
const { Graduatoria } = require('../models/graduatoria');

const Product = require('../models/product');
const Producer = require('../models/producer');
const Cart = require('../models/cart');
const OrdersCart = require('../models/orderscart');
const Storehouse = require('../models/storehouse');
const Provider = require('../models/provider');
const Gasordine = require('../models/gasordine');
const Scontistica = require('../models/scontistica');
const Department = require('../models/department');
const CatProd = require('../models/catprod');
const Collana = require('../models/collana');
const CatAI = require('../models/catai');
const { QueryAI } = require('../models/queryai');
const SubCatProd = require('../models/subcatprod');
const T_Web_StatiProdotto = require('../models/t_web_statiprodotto');
const T_Web_Tipologie = require('../models/t_web_tipologie');
const { Category } = require('../models/category');
const ShareWithUs = require('../models/sharewithus');
const Site = require('../models/site');
const IscrittiConacreis = require('../models/iscrittiConacreis');
const Group = require('../models/group');
const { Todo } = require('../models/todo');
const Hours = require('../models/hours');
const Order = require('../models/order');
const CashCategory = require('../models/cashCategory');
const CashSubCategory = require('../models/cashSubCategory');

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

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

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

module.exports = {
  isTableReaction(tablename) {
    return shared_consts.TABLES_REACTIONS.includes(tablename);
  },

  getTableByTableName(tablename) {
    let mytable = '';
    if (tablename === 'users') mytable = User;
    else if (tablename === shared_consts.TAB_MYGROUPS) mytable = MyGroup;
    else if (tablename === 'tessitura') mytable = Tessitura;
    // else if (tablename === 'extralist')
    //   mytable = ExtraList;
    else if (tablename === 'bookings') mytable = Booking;
    else if (tablename === 'operators') mytable = Operator;
    else if (tablename === 'products') mytable = Product;
    else if (tablename === 'arrvariazioni') mytable = Product;
    else if (tablename === 'storehouses') mytable = Storehouse;
    else if (tablename === 'providers') mytable = Provider;
    else if (tablename === 'gasordines') mytable = Gasordine;
    else if (tablename === 'scontisticas') mytable = Scontistica;
    else if (tablename === 'departments') mytable = Department;
    else if (tablename === 'categorys') mytable = Category;
    else if (tablename === 'catprods') mytable = CatProd;
    else if (tablename === 'collanas') mytable = Collana;
    else if (tablename === 'catais') mytable = CatAI;
    else if (tablename === 'queryais') mytable = QueryAI;
    else if (tablename === 'subcatprods') mytable = SubCatProd;
    else if (tablename === 't_web_statiprodottos') mytable = T_Web_StatiProdotto;
    else if (tablename === 't_web_tipologies') mytable = T_Web_Tipologie;
    else if (tablename === 'sharewithus') mytable = ShareWithUs;
    else if (tablename === 'sites') mytable = Site;
    else if (tablename === 'iscritticonacreis') mytable = IscrittiConacreis;
    else if (tablename === 'groups') mytable = Group;
    else if (tablename === 'todos') mytable = Todo;
    else if (tablename === 'hours') mytable = Hours;
    else if (tablename === 'orders') mytable = Order;
    else if (tablename === 'cashs') mytable = Cash;
    else if (tablename === 'cashCategorys') mytable = CashCategory;
    else if (tablename === 'cashSubCategorys') mytable = CashSubCategory;
    else if (tablename === 'producers') mytable = Producer;
    else if (tablename === 'carts') mytable = Cart;
    else if (tablename === 'orderscarts') mytable = OrdersCart;
    else if (tablename === 'sendmsgs') mytable = SendMsg;
    else if (tablename === 'wheres') mytable = Where;
    else if (tablename === 'myevents') mytable = MyEvent;
    else if (tablename === 'contribtypes') mytable = Contribtype;
    else if (tablename === 'paymenttypes') mytable = PaymentType;
    else if (tablename === 'disciplines') mytable = Discipline;
    else if (tablename === 'newstosent') mytable = Newstosent;
    else if (tablename === 'gallery') mytable = Gallery;
    else if (tablename === 'mypages' || tablename === 'mypage') mytable = MyPage;
    else if (tablename === 'myelems') mytable = MyElem;
    else if (tablename === 'myscrapingbooks') mytable = MyScrapingBook;
    else if (tablename === 'crons') mytable = Cron;
    else if (tablename === 'myschedas') mytable = MyScheda;
    else if (tablename === 'bots') mytable = MyBot;
    else if (tablename === 'cfgservers') mytable = CfgServer;
    else if (tablename === 'calzoom') mytable = CalZoom;
    else if (tablename === 'templemail') mytable = TemplEmail;
    else if (tablename === 'destnewsletter') mytable = DestNewsletter;
    else if (tablename === 'opzemail') mytable = OpzEmail;
    else if (tablename === 'settings') mytable = Settings;
    else if (tablename === 'permissions') mytable = Permission;
    else if (tablename === 'mailinglist') mytable = MailingList;
    else if (tablename === 'msg_templates') mytable = MsgTemplate;
    else if (tablename === 'navepersistente') mytable = NavePersistente;
    // else if (tablename === 'listaingressos')
    //   mytable = ListaIngresso;
    else if (tablename === 'graduatorias') mytable = Graduatoria;
    else if (tablename === 'skills') mytable = Skill;
    else if (tablename === 'catalogs') mytable = Catalog;
    else if (tablename === 'raccoltacataloghis') mytable = RaccoltaCataloghi;
    else if (tablename === 'goods') mytable = Good;
    else if (tablename === 'bachecas') mytable = Bacheca;
    else if (tablename === 'subskills') mytable = SubSkill;
    else if (tablename === shared_consts.TABLES_MYSKILLS) mytable = MySkill;
    else if (tablename === shared_consts.TABLES_ATTIVITAS) mytable = Attivita;
    else if (tablename === shared_consts.TABLES_MYBACHECAS) mytable = MyBacheca;
    else if (tablename === shared_consts.TABLES_MYHOSPS) mytable = MyHosp;
    else if (tablename === shared_consts.TABLES_MYGOODS) mytable = MyGood;
    else if (tablename === 'statusSkills') mytable = StatusSkill;
    else if (tablename === 'cities') mytable = City;
    else if (tablename === 'provinces') mytable = Province;
    else if (tablename === 'sectors') mytable = Sector;
    else if (tablename === 'sectorgoods') mytable = SectorGood;
    else if (tablename === 'catgrps') mytable = CatGrp;
    else if (tablename === 'levels') mytable = Level;
    else if (tablename === 'adtypes') mytable = AdType;
    else if (tablename === 'adtypegoods') mytable = AdTypeGood;
    else if (tablename === 'circuits') mytable = Circuit;
    else if (tablename === 'accounts') mytable = Account;
    else if (tablename === 'movements') mytable = Movement;
    else if (tablename === 'reactions') mytable = Reaction;
    else if (shared_consts.TablePickup.includes(tablename)) mytable = Pickup;
    //else if (shared_consts.TableCities.includes(tablename))
    // mytable = City;

    return mytable;
  },

  checkifSendPushNotification() {
    return process.env.ENABLE_PUSHNOTIFICATION === '1';
  },

  async sendNotifCmd(typenotif, idnotif, res, idapp, user, recnotif, paramsObj) {
    // Controlla nelle impostazioni che tipo di Notifica visualizzare

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

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

    /// ... rivedere il crea gruppo... notifiche...
    try {
      if (!recnotif.typesend) {
        recnotif.typesend =
          shared_consts.MessageOptions.Notify_ByPushNotification + shared_consts.MessageOptions.Notify_ByBotTelegram;
      }

      let invia = false;

      let params = {
        idapp,
        sendreally: true,
        typesend: 0,
        title: tools.getNomeAppByIdApp(idapp),
        content: recnotif.descr ? recnotif.descr : tools.getContentByTypeMsg(recnotif.typemsg),
        openUrl: tools.updateQueryStringParameter(recnotif.openUrl, 'idnotif', recnotif._id),
        typemsg: recnotif.typemsg ? recnotif.typemsg : shared_consts.TypeMsg.SEND_TO_USER,
        typenotif,
        idnotif,
        img: recnotif.img,
        usernameDest: recnotif.usernameDest ? recnotif.usernameDest : recnotif.dest,
        tag: recnotif.tag ? recnotif.tag : '',
        actions: recnotif.actions ? recnotif.actions : [],
        id: recnotif._id,
        textaddTelegram: recnotif.textaddTelegram ? recnotif.textaddTelegram : '',
        textcontent_Telegram: recnotif.textcontent_Telegram ? recnotif.textcontent_Telegram : '',
        linkaddTelegram: recnotif.linkaddTelegram ? recnotif.linkaddTelegram : '',
        inviaaListaUtenti: recnotif.inviaaListaUtenti,
      };

      if (
        tools.isBitActive(recnotif.typesend, shared_consts.MessageOptions.Notify_ByPushNotification) &&
        this.checkifSendPushNotification
      ) {
        params.typesend = params.typesend + shared_consts.TypeSend.PUSH_NOTIFICATION;
        invia = true;
      }
      if (tools.isBitActive(recnotif.typesend, shared_consts.MessageOptions.Notify_ByBotTelegram)) {
        params.typesend = params.typesend + shared_consts.TypeSend.TELEGRAM;
        invia = true;
      }

      if (recnotif.extrarec?.send_email) {
        params.typesend = params.typesend + shared_consts.TypeSend.EMAIL;
      }

      if (invia) {
        ris = await this.SendMsgToParam(idapp, params, recnotif, paramsObj);
      }

      // Send Msg by EMAIL
      if (tools.isBitActive(recnotif.typesend, shared_consts.MessageOptions.Notify_ByEmail)) {
        // Read from the operator table first
        let emaildest = await Operator.getEmailByUsername(recnotif.dest.idapp, recnotif.dest.username);
        if (!emaildest) emaildest = await User.getEmailByUsername(recnotif.dest.idapp, recnotif.dest.username);

        await sendemail.sendEmail_ByNotif(res, user.lang, emaildest, user, idapp, recnotif);
      }

      return recnotif;
    } catch (e) {
      console.error('sendNotif', e, typenotif, recnotif);
      return recnotif;
    }
  },

  SendMsgToParam: async function (idapp, params, recnotif, paramsObj) {
    try {
      // console.log('SendMsgToParam', params.typesend, params.typemsg);

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

      let textsent = '';

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

      if (params.typesend === 0) params.typesend = shared_consts.TypeSend.PUSH_NOTIFICATION;

      let query = { idapp };
      let addquery = {};

      let invia = true;

      if (params.typemsg === shared_consts.TypeMsg.SEND_TO_ALL) {
        addquery = {};
      } else if (params.typemsg === shared_consts.TypeMsg.SEND_TO_SOCI) {
        addquery = { 'profile.socio': true };
      } else if (params.typemsg === shared_consts.TypeMsg.SEND_TO_SOCIO_RESIDENTE) {
        addquery = { 'profile.socioresidente': true };
      } else if (params.typemsg === shared_consts.TypeMsg.SEND_TO_CONSIGLIO) {
        addquery = { 'profile.consiglio': true };
      } else if (params.typemsg === shared_consts.TypeMsg.SEND_TO_NON_SOCI) {
        addquery = { 'profile.socio': false };
      } else if (params.typemsg === shared_consts.TypeMsg.SEND_TO_PAOLO) {
        addquery = { username: shared_consts.ADMIN_USER_SERVER };
      } else if (params.typemsg === shared_consts.TypeMsg.SEND_TO_USER) {
        addquery = { username: params.usernameDest };
      } else if (params.typemsg === shared_consts.TypeMsg.SEND_TO_MYSELF) {
        addquery = { username: params.usernameDest };
      } else if (params.typemsg === shared_consts.TypeMsg.SEND_TO_TELEG_NO_USERNAME_TELEG) {
        addquery = {
          'profile.teleg_id': { $gt: 1 },
          $or: [
            { 'profile.username_telegram': { $exists: false } },
            { 'profile.username_telegram': { $exists: true, $eq: '' } },
          ],
        };
      } else if (params.typemsg === shared_consts.TypeMsg.SEND_TO_TELEG_NO_VERIF_BY_APORTADOR) {
        addquery = {
          'profile.teleg_id': { $gt: 1 },
          'profile.username_telegram': { $exists: true },
          $expr: { $gt: [{ $strLenCP: '$profile.username_telegram' }, 3] },
          verified_by_aportador: { $exists: false },
        };
      } else if (params.typemsg === shared_consts.TypeMsg.SEND_TO_GROUP) {
        if (params.groupnameDest) {
          addquery = {
            'profile.mygroups': {
              $elemMatch: { groupname: { $eq: params.groupnameDest } },
            },
          };
        } else {
          invia = false;
        }
      } else if (params.typemsg === shared_consts.TypeMsg.SEND_TO_CIRCUIT) {
        if (params.circuitnameDest) {
          addquery = {
            'profile.mycircuits': {
              $elemMatch: { circuitname: { $eq: params.circuitnameDest } },
            },
          };
        } else {
          invia = false;
        }
      }

      let numrec = 0;
      let nummsgsent = 0;
      let text = '';

      if (invia) {
        const allquery = { ...query, ...addquery };

        let arrusers = await User.find(allquery, {
          username: 1,
          'profile.teleg_id': 1,
          'profile.notifs': 1,
        }).lean();

        if (!tools.sulServer()) {
          if (allquery && allquery.username && shared_consts.ADMIN_IDTELEGRAM_TEST_USERNAME.includes(allquery.username)) {
            // Sto usando un username di test.
          } else {
            arrusers = await User.find({ idapp, username: shared_consts.ADMIN_USER_SERVER });
          }
        }

        for (const user of arrusers) {
          try {
            const mytitle = await tools.convertSpecialTags(user, params.title);
            const mycontent = await tools.convertSpecialTags(
              user,
              params.textcontent_Telegram ? params.textcontent_Telegram : params.content
            );

            let usernotifprofile = null;
            if (user.profile.notifs)
              usernotifprofile = user.profile.notifs.find((notif) => notif.dir === params.typenotif);

            let risult = null;

            let sendmsg = false;

            if (params.typenotif === shared_consts.TypeNotifs.TYPEDIR_FAVORITE) {
              if (
                !usernotifprofile ||
                (usernotifprofile &&
                  tools.isBitActive(usernotifprofile.value, shared_consts.TypeNotifs.ID_FAVORITE_ADDED))
              ) {
                sendmsg = true;
              }
            } else {
              sendmsg = true;
            }

            if (sendmsg) {
              if (params.sendreally) {
                if (tools.isBitActive(params.typesend, shared_consts.TypeSend.PUSH_NOTIFICATION)) {
                  const myparam = { ...params };
                  risult = await tools
                    .sendNotificationToUser(
                      user._id,
                      mytitle,
                      mycontent,
                      myparam.openUrl,
                      myparam.openUrl2,
                      myparam.tag,
                      myparam.actions,
                      myparam.id
                    )
                    .then((ris) => { })
                    .catch((e) => {
                      console.error(e.message);
                    });
                }
                if (tools.isBitActive(params.typesend, shared_consts.TypeSend.TELEGRAM)) {
                  const telegid = user.profile.teleg_id;

                  text = tools.getContentNotifByParams(params, mycontent, shared_consts.TypeSend.TELEGRAM);
                  if (telegid > 0) {
                    risult = await telegrambot.local_sendMsgTelegramByIdTelegram(
                      idapp,
                      telegid,
                      text,
                      undefined,
                      undefined,
                      undefined,
                      undefined,
                      params.img,
                      params
                    );
                    await tools.snooze(25);

                    try {
                      if (risult && (risult.text || risult.caption)) textsent = risult.text || risult.caption;
                    } catch (e) { }
                  }
                }
                if (tools.isBitActive(params.typesend, shared_consts.TypeSend.EMAIL)) {
                  // Invia una Email
                  if (params.tag === 'setfido') {
                    const usertosend = await User.getUserByUsername(params.idapp, params.usernameDest);
                    if (paramsObj) {
                    }
                    
                    const dati = {
                      usernameInvitante: paramsObj.extrarec?.username_admin_abilitante,
                      nomeTerritorio: paramsObj.circuitnameDest,
                      link_group: paramsObj.extrarec?.link_group,
                      circuitId: paramsObj.circuitId,
                    };
                    await sendemail.sendEmail_Utente_Abilitato_Circuito_FidoConcesso(usertosend.lang, usertosend.email, usertosend, params.idapp, dati);
                  }
                }
              }

              numrec++;
              if (params.sendreally && risult) {
                nummsgsent++;
              }

              if (nummsgsent > 0 && nummsgsent % 100 === 0) {
                console.log('Inviati ', nummsgsent, 'messaggi...');
              }
            }
          } catch (e) {
              console.error('Errore Invio Notifica a ', user.username, 'Err:', e);
          }
        }
      }

      if (nummsgsent > 0) {
        if (nummsgsent != numrec && numrec !== 1)
          console.log('FINE Invio Messaggi ! Inviati Totali: ', nummsgsent, 'su', numrec);
      }

      return {
        numrec,
        nummsgsent,
        textsent,
        text,
      };
    } catch (e) {
      console.error('SendMsgToParam', e);
    }
  },

  SendMsgToAll: async function (idapp, params) {
    params.typemsg = shared_consts.TypeMsg.SEND_TO_ALL;
    params.sendreally = true;
    params.typesend = shared_consts.TypeSend.PUSH_NOTIFICATION;

    return await this.SendMsgToParam(idapp, params, null);
  },

  SearchString: async function (idapp, searchString) {
    const db = mongoose.connection.db;
    let result = '';
    let resultPrima = '';

    if (!searchString) return '';

    try {
      // Ottieni tutte le collezioni del database
      const collections = await db.listCollections().toArray();
      const collectionNames = collections.map((collection) => collection.name);

      for (const collectionName of collectionNames) {
        // Crea l'indice di testo per la collezione
        await db.collection(collectionName).createIndex({ '$**': 'text' });

        if (collectionName !== 'sendnotifs') {
          // Cerca nella collezione
          const found = await db
            .collection(collectionName)
            .find({
              $and: [
                { idapp: idapp },
                { $text: { $search: searchString } },
                { 'profile.username_telegram': { $exists: false } },
              ],
            })
            .toArray();

          if (found.length > 0) {
            resultPrima += `Risultati trovati nella collezione: ${collectionName} (${found.length} record)\n`;

            result += `Risultati trovati nella collezione: ${collectionName}\n`;
            for (const record of found) {
              result += JSON.stringify(record) + '\n';
            }
            result += '\n';
          }
        }
      }

      if (result === '') {
        result = 'La stringa non è stata trovata in nessuna collezione.';
      }
    } catch (error) {
      result = `Errore durante la ricerca: ${error.message}`;
    } finally {
    }

    return resultPrima + '\n\n' + result;
  },

  replaceAportadorSolidario: async function (idapp, search_username, replace_username) {
    console.log('INIZIO replaceAportadorSolidario');

    if (!search_username || !replace_username) {
      return false;
    }

    ris = await User.updateMany(
      { idapp, aportador_iniziale: search_username },
      {
        $set: { aportador_iniziale: replace_username },
      }
    );
    console.log('aportador_iniziale result = ', ris);

    ris = await User.updateMany(
      { idapp, aportador_solidario: search_username },
      {
        $set: { aportador_solidario: replace_username },
      }
    );
    console.log('aportador_solidario result = ', ris);
  },
  replaceUsername: async function (idapp, search_username, replace_username) {
    if (!search_username || !replace_username) {
      return false;
    }

    const test = false;

    console.log('INIZIO replaceUsername');

    try {
      let ris = null;
      console.log('replaceUsername = ', search_username, replace_username);

      const dir = tools.getdirByIdApp(idapp, true);

      tools.move(
        dir + server_constants.DIR_UPLOAD + '/profile/' + search_username,
        dir + server_constants.DIR_UPLOAD + '/profile/' + replace_username,
        function callback() {
          console.log(
            ' ... moved dir',
            dir + server_constants.DIR_UPLOAD + '/profile/' + search_username,
            dir + server_constants.DIR_UPLOAD + '/profile/' + replace_username
          );
        }
      );

      if (test) {
        // esco...
      } else {
        ris = await User.findOneAndUpdate(
          { idapp, username: search_username },
          { $set: { username: replace_username } }
        );
        console.log('username result = ', ris);

        ris = await User.findOneAndUpdate(
          { idapp, username: search_username },
          { $set: { username: replace_username } }
        );
        console.log('username result = ', ris);

        ris = await User.findOneAndUpdate(
          { idapp, 'profile.username_telegram': search_username },
          { $set: { 'profile.username_telegram': replace_username } }
        );
        console.log('profile.username_telegram result = ', ris);

        ris = await User.updateMany(
          { idapp, aportador_iniziale: search_username },
          {
            $set: { aportador_iniziale: replace_username },
          }
        );
        console.log('aportador_iniziale result = ', ris);

        ris = await User.updateMany(
          { idapp, username_who_report: search_username },
          {
            $set: { username_who_report: replace_username },
          }
        );
        console.log('username_who_report result = ', ris);

        ris = await User.updateMany(
          { idapp, aportador_solidario: search_username },
          {
            $set: { aportador_solidario: replace_username },
          }
        );
        console.log('aportador_solidario result = ', ris);

        ris = await User.updateMany(
          { idapp, 'profile.friends.username': search_username },
          {
            $set: { 'profile.friends.$.username': replace_username },
          }
        );
        console.log('friends.username result = ', ris);

        ris = await User.updateMany(
          { idapp, 'profile.req_friends.username': search_username },
          {
            $set: { 'profile.req_friends.$.username': replace_username },
          }
        );
        console.log('req_friends.username result = ', ris);

        ris = await User.updateMany(
          { idapp, 'profile.handshake.username': search_username },
          {
            $set: { 'profile.handshake.$.username': replace_username },
          }
        );
        console.log('handshake.username result = ', ris);

        ris = await Circuit.updateMany(
          { idapp, 'admins.username': search_username },
          { $set: { 'admins.$.username': replace_username } }
        );
        console.log('Circuit.admins.username result = ', ris);

        ris = await Circuit.updateMany(
          { idapp, createdBy: search_username },
          { $set: { createdBy: replace_username } }
        );
        console.log('Circuit.createdBy result = ', ris);

        ris = await MyGroup.updateMany(
          { idapp, createdBy: search_username },
          { $set: { createdBy: replace_username } }
        );
        console.log('MyGroup.createdBy result = ', ris);

        ris = await MyElem.updateMany(
          {
            idapp,
            $or: [
              { containerHtml: { $regex: search_username, $options: 'i' } },
              { link: { $regex: search_username, $options: 'i' } },
            ],
          },
          [
            {
              $set: {
                containerHtml: {
                  $replaceAll: {
                    input: '$containerHtml',
                    find: search_username,
                    replacement: replace_username,
                  },
                },
                link: {
                  $replaceAll: {
                    input: '$link',
                    find: search_username,
                    replacement: replace_username,
                  },
                },
              },
            },
          ]
        );

        console.log('MyElem.containerHtml result = ', ris);

        ris = await Circuit.updateMany(
          { idapp, 'req_users.username': search_username },
          { $set: { 'req_users.$.username': replace_username } }
        );
        console.log('Circuit.req_users.username result = ', ris);

        ris = await Circuit.updateMany(
          { idapp, 'refused_users.username': search_username },
          { $set: { 'refused_users.$.username': replace_username } }
        );
        console.log('Circuit.refused_users.username result = ', ris);

        ris = await Account.updateMany({ idapp, username: search_username }, { $set: { username: replace_username } });
        console.log('Account.username result = ', ris);

        ris = await MyGroup.updateMany(
          { idapp, 'admins.username': search_username },
          { $set: { 'admins.$.username': replace_username } }
        );
        console.log('MyGroup.refused_users.username result = ', ris);

        ris = await MyGroup.updateMany(
          { idapp, 'req_users.username': search_username },
          { $set: { 'req_users.$.username': replace_username } }
        );
        console.log('MyGroup.req_users.username result = ', ris);

        // MyGroup.refused_users.username
        ris = await MyGroup.updateMany(
          { idapp, 'refused_users.username': search_username },
          { $set: { 'refused_users.$.username': replace_username } }
        );
        console.log('MyGroup.refused_users.username result = ', ris);

        const { SendNotif } = require('../models/sendnotif');

        ris = await SendNotif.updateMany({ idapp, sender: search_username }, { $set: { sender: replace_username } });
        console.log('SendNotif.sender result = ', ris);

        try {
          ris = await SendNotif.updateMany({ idapp, dest: search_username }, { $set: { dest: replace_username } });
          console.log('SendNotif.dest result = ', ris);
        } catch (e) {
          console.error(e);
        }

        ris = await Reaction.updateMany({ idapp, username: search_username }, { $set: { username: replace_username } });
        console.log('Reaction.dest result = ', ris);

        ris = await SendMsg.updateMany({ idapp, dest: search_username }, { $set: { dest: replace_username } });
        console.log('SendMsg.dest result = ', ris);

        ris = await SendMsg.updateMany({ idapp, origin: search_username }, { $set: { origin: replace_username } });
        console.log('SendMsg.origin result = ', ris);

        ris = await Booking.updateMany({ idapp, username: search_username }, { $set: { username: replace_username } });
        console.log('Booking.username result = ', ris);
      }
    } catch (e) {
      console.error(e);
    }
  },

  getNumFavoriteByIdObj: async function (idapp, numtab, id) {
    const { Reaction } = require('../models/reaction');

    let query = [
      {
        $match: {
          idapp,
          idrec: id,
        },
      },
      {
        $group: {
          _id: null,
          count: {
            $sum: {
              $cond: {
                if: { $ifNull: ['$fav', false] }, // Check if the field exists and is not null
                then: 1, // Increment count by 1 if the field exists
                else: 0, // Otherwise, keep the count unchanged
              },
            },
          },
        },
      },
      { $project: { _id: 0 } },
    ];

    try {
      const [result] = await Reaction.aggregate(query);

      return result ? result.count : 0;
    } catch (err) {
      return 0;
    }

    return 0;
  },

  getNumBookByIdObj: async function (idapp, numtab, id) {
    const { Reaction } = require('../models/reaction');

    let query = [
      {
        $match: {
          idapp,
          idrec: id,
        },
      },
      {
        $group: {
          _id: null,
          count: {
            $sum: {
              $cond: {
                if: { $ifNull: ['$book', false] }, // Check if the field exists and is not null
                then: 1, // Increment count by 1 if the field exists
                else: 0, // Otherwise, keep the count unchanged
              },
            },
          },
        },
      },
      { $project: { _id: 0 } },
    ];

    try {
      const [result] = await Reaction.aggregate(query);

      return result ? result.count : 0;
    } catch (err) {
      return 0;
    }

    return 0;
  },

  getNumAttendByIdObj: async function (idapp, numtab, id) {
    const { Reaction } = require('../models/reaction');

    let query = [
      {
        $match: {
          idapp,
          idrec: id,
        },
      },
      {
        $group: {
          _id: null,
          count: {
            $sum: {
              $cond: {
                if: { $ifNull: ['$attent', false] }, // Check if the field exists and is not null
                then: 1, // Increment count by 1 if the field exists
                else: 0, // Otherwise, keep the count unchanged
              },
            },

            /*$sum:
            {
              $reduce: {
                input: "$profile.attend",
                initialValue: 0,
                in: {
                  $add: ["$$value", "$$this.num"]
                }
              }
            }*/
          },
        },
      },
      { $project: { _id: 0 } },
    ];

    try {
      const [result] = await Reaction.aggregate(query);

      return result ? result.count : 0;
    } catch (err) {
      return 0;
    }
  },

  getUserCreatorByNumTabAndId: async function (idapp, id, numtab) {
    try {
      const table = tools.getTableByNumTab(numtab);
      const mytable = this.getTableByTableName(table);

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

      if (mytable) {
        const rec = await mytable.findOne({ _id: id, idapp }, { username: 1, lang: 1, userId: 1, descr: 1 });
        if (rec) {
          const recuser = await User.getUserById(idapp, rec.userId);

          let numattend = await this.getNumAttendByIdObj(idapp, numtab, id);
          let numfav = await this.getNumFavoriteByIdObj(idapp, numtab, id);
          let numbook = await this.getNumBookByIdObj(idapp, numtab, id);
          let exist = false;
          if (table === shared_consts.TABLES_MYBACHECAS) exist = numattend > 1;
          else exist = numfav > 1;
          if (recuser)
            return {
              userId: rec.userId,
              username: recuser.username,
              descr: rec.descr,
              id: rec._id,
              table,
              exist,
              numfav,
              numattend,
              numbook,
            };
        }
      }
    } catch (e) {
      console.error('Err:', e);
    }

    return null;
  },

  async removeAdminIfZeroBalance(idapp, username) {
    try {
      // Trova l'account con saldo_pend a zero
      const accountarr = await Account.find({ idapp, username: username, saldo_pend: 0 }).lean();

      if (accountarr) {
        for (const recaccount of accountarr) {
          // Rimuovi l'username dalla lista degli admins nel Circuit
          const ris = await Circuit.findOneAndUpdate(
            { _id: recaccount.circuitId },
            { $pull: { admins: { username: username } } }, // Rimuove l'username dalla lista degli admins
            { new: true } // Opzione per restituire il documento aggiornato
          );

          const nomecircuito = ris.name;

          // Esco anche dal Circuito personale:
          await User.findOneAndUpdate(
            { idapp, username },
            { $pull: { 'profile.mycircuits': { circuitname: nomecircuito } } }
          );

          if (ris) console.log(`L'username ${username} è stato rimosso dagli admins di ` + nomecircuito);
        }
      } else {
        console.log(`Nessun account trovato con saldo_pend a zero per l'username: ${username}.`);
      }
    } catch (error) {
      console.error("Errore durante l'operazione:", error);
    }
  },

  async ExitFromAllCircuitWithZero(idapp, username) {
    return await this.removeAdminIfZeroBalance(idapp, username);
  },

  async clonePage(idapp, idPageOrig, newName, newPath) {
    try {
      // Recupera la pagina originale
      const page = await MyPage.findOne({ _id: idPageOrig }).lean();
      if (!page) {
        console.log('Pagina originale non trovata.');
        return;
      }
  
      // Clona la pagina rimuovendo l'_id e aggiungendo un nuovo nome
      const clonedPage = {
        ...page, _id: new mongoose.Types.ObjectId(),
        title: newName,
        path: newPath,
        isTemplate: false,
      };
  
      // Salva la pagina clonata
      const savedPage = await MyPage.create(clonedPage);
      console.log('Pagina clonata con successo:', savedPage._id);
      return savedPage;

    } catch (error) {
      console.error('Errore durante la clonazione della pagina:', error);
    }
  },

  async cloneCatalog(idapp, idOrig, newName, idPageAssigned, referenti) {
    try {
      // Recupera il catalogo originale
      const mycatalog = await Catalog.findOne({ idapp, _id: idOrig }).lean();
      if (!mycatalog) {
        console.log('Catalogo originale non trovato.');
        return;
      }
  
      // Clona la pagina rimuovendo l'_id e aggiungendo un nuovo nome
      const clonedCatalog = {
        _id: new mongoose.Types.ObjectId(),
        idapp,
        active: true,
        title: newName,
        foto_collana: mycatalog.foto_collana,
        idCollane: mycatalog.idCollane,
        idTipoFormato: mycatalog.idTipoFormato,
        argomenti: mycatalog.argomenti,
        condition_andor: mycatalog.condition_andor,
        editore: mycatalog.editore,
        editore_escludi: mycatalog.editore_escludi,
        descr_introduttiva: '',
        img_bordata: mycatalog.img_bordata,
        img_intro: mycatalog.img_intro,
        img_bordata_stampa: mycatalog.img_bordata_stampa,
        disattiva_link_immagini: mycatalog.disattiva_link_immagini,
        img_intro_stampa: mycatalog.img_intro_stampa,
        pagina_introduttiva_sfondo_nero: mycatalog.pagina_introduttiva_sfondo_nero,
        backcolor: mycatalog.backcolor,
        idPageAssigned: idPageAssigned,
        referenti,
      };

      const mydirpath = tools.getdirByIdApp(idapp);

      // copia i file nella sua sottocartella del catalogo
      const sourceDir = path.join(mydirpath, tools.getDirUpload(), shared_consts.getDirectoryByTable(shared_consts.TABLES_CATALOG), idOrig);
      const destinationDir = path.join(mydirpath, tools.getDirUpload(), shared_consts.getDirectoryByTable(shared_consts.TABLES_CATALOG), clonedCatalog._id.toString());

      await tools.copyDirectory(sourceDir, destinationDir);  
  
      // Salva la pagina clonata
      const savedCatalog = await Catalog.create(clonedCatalog);

      return savedCatalog;
      console.log('Catalogo clonato con successo:', savedCatalog._id);
    } catch (error) {
      console.error('Errore durante la clonazione del Catalogo:', error);
    }
  },

  async newEmptyCatalog(idapp, newName, idPageAssigned, referenti) {
    try {
  
      const clonedCatalog = {
        _id: new mongoose.Types.ObjectId(),
        active: true,
        title: newName,
        idPageAssigned: idPageAssigned,
        referenti,
      };
  
      // Salva la pagina
      const savedCatalog = await Catalog.create(clonedCatalog);

      return savedCatalog;
      console.log('Catalogo creato con successo:', savedCatalog._id);
    } catch (error) {
      console.error('Errore durante la clonazione del Catalogo:', error);
    }
  },

  async duplicatePage(pageId, newpath, title = '') {
    try {
      // Trova il record di Page da duplicare
      const pageToDuplicate = await MyPage.findById(pageId);
      if (!pageToDuplicate) {
        console.error('Page not found.');
        return;
      }
  
      // Crea una copia del record di Page
      const newPage = new MyPage({
        ...pageToDuplicate.toObject(), // Converte il documento Moongose in oggetto
        _id: new mongoose.Types.ObjectId(), // Genera un nuovo ID
        // modifiche ai campi se necessario, per esempio:
        path: newpath,
        title: title || newpath,
        subtitle: '',
        inmenu: false,
        active: true,
        date_updated: new Date(),
        isTemplate: false,
        author_username: '',
      });
  
      // Salva il nuovo record di Page
      await newPage.save();
  
      // Trova tutti gli elementi associati a Page da duplicare
      const elemsToDuplicate = await MyElem.find({ idPage: pageId }).lean();
  
      // Duplica ogni elemento utilizzando il nuovo idPath
      const duplicates = elemsToDuplicate.map((elem) => {
        const catalogo = elem.catalogo;
  
        if (catalogo) {
          for (const recscheda of catalogo.arrSchede) {
            if (recscheda.scheda?.isTemplate) {
              // Se è un template allora devo mettergli un altro ID !
              recscheda.scheda._id = new mongoose.Types.ObjectId();
              // recscheda.scheda.name = getNewFreeNameTemplate(recscheda.scheda?.name)
            }
          }
        }
  
        if (catalogo) elem.catalogo = { ...catalogo };
  
        const newElem = new MyElem({
          ...elem, // Copia le proprietà dell'elemento
          _id: new mongoose.Types.ObjectId(), // Genera un nuovo ID
          idPage: newPage._id.toString(), // Imposta il nuovo campo IdPage
          path: newPage.path,
        });
  
        return newElem;
      });
  
      // Salva tutti gli elementi duplicati
      await MyElem.insertMany(duplicates);

      const newElems = await MyElem.find({ idPage: newPage._id }).lean();
  
      // console.log('Duplicazione completata con successo.');
      const newPageOut = await MyPage.findById(newPage._id).lean();

      return { newPage: newPageOut, newElems };

    } catch (error) {
      console.error('Errore durante la duplicazione:', error);
      return { newPage: null, newElems: null };
    }
  },

  async addNewCatalog(idapp, newCatalog, username) {
  try {
    if (newCatalog) {
      const myNewrecs = await this.duplicatePage(newCatalog.idPageTemplate, newCatalog.path, newCatalog.title);
      // Clonare la pagina MyPage che rappresenta il modello newCatalog.idPageTemplate su newCatalog.path
      if (!myNewrecs?.newPage) {
        console.error('Errore durante la clonazione della pagina del catalogo');
        return { newPage: null, newCatalog: null, newElems: null };
      }
  
      let mynewCatalog = null;
        
      if (newCatalog.idCatalogToCopy) {
  
        mynewCatalog = await this.cloneCatalog(
          idapp,
          newCatalog.idCatalogToCopy,
          newCatalog.title,
          myNewrecs?.newPage._id,
          [username],
        );
      } else {
        mynewCatalog = await this.newEmptyCatalog(
          idapp,
          newCatalog.title,
          myNewrecs?.newPage._id,
          [username],
        );
          
      }
  
      return { newPage: myNewrecs?.newPage, newElems: myNewrecs?.newElems, newCatalog: mynewCatalog };
    }
  } catch (e) {
    console.error("Errore durante l'aggiunta del catalogo:", e);
    return { newPage: null, newCatalog: null, newElems: null };
  }
},  
  
  
};
