const os = require('os');

const fs = require('fs');

const path = require('path');

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

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

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

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 { Good } = require('../models/good');
const { SubSkill } = require('../models/subskill');
const { MySkill } = require('../models/myskill');
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 { 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 { 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 Department = require('../models/department');
const { Category } = require('../models/category');
const ShareWithUs = require('../models/sharewithus');
const Site = require('../models/site');
const IscrittiConacreis = require('../models/iscrittiConacreis');
const IscrittiArcadei = require('../models/iscrittiArcadei');
const Group = require('../models/group');
const { Todo } = require('../models/todo');
const Hours = require('../models/hours');
const Order = require('../models/order');
const Cash = require('../models/cash');
const CashCategory = require('../models/cashCategory');
const CashSubCategory = require('../models/cashSubCategory');

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

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


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 === 'storehouses')
      mytable = Storehouse;
    else if (tablename === 'departments')
      mytable = Department;
    else if (tablename === 'categorys')
      mytable = Category;
    else if (tablename === 'sharewithus')
      mytable = ShareWithUs;
    else if (tablename === 'sites')
      mytable = Site;
    else if (tablename === 'iscritticonacreis')
      mytable = IscrittiConacreis;
    else if (tablename === 'iscrittiarcadei')
      mytable = IscrittiArcadei;
    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 === 'orderscart')
      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 === 'mypage')
      mytable = MyPage;
    else if (tablename === 'myelems')
      mytable = MyElem;
    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 === '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 === 'goods')
      mytable = Good;
    else if (tablename === 'subskills')
      mytable = SubSkill;
    else if (tablename === shared_consts.TABLES_MYSKILLS)
      mytable = MySkill;
    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 sendNotif(typenotif, idnotif, res, idapp, user, recnotif, cmd) {
    // 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,
        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 : '',
      };
      
      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 (invia) {
        ris = await this.SendMsgToParam(idapp, params);
      }

      // 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) {

    try {
      // console.log('SendMsgToParam', params.typesend, params.typemsg);

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

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

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


        for (const user of arrusers) {

          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);
                  await tools.snooze(25);

                  textsent = risult.text;
                }
              }
            }

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

            if (nummsgsent > 0 && (nummsgsent % 100) === 0) {
              console.log('Inviati ', nummsgsent, 'messaggi...');
            }
          }
        }
      }

      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);
  },

  replaceUsername: async function (idapp, search_username, replace_username) {

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

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

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

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

      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, '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);


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


};
