const express = require('express');
const router = express.Router();

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

const ListaInvitiEmail = require('../models/listainvitiemail');

// const { Nave } = require('../models/nave');
const Hours = require('../models/hours');
//const { NavePersistente } = require('../models/navepersistente');
//const { ListaIngresso } = require('../models/listaingresso');
//const { Graduatoria } = require('../models/graduatoria');
// const { ExtraList } = require('../models/extralist');
const { ObjectId } = require('mongodb');

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

const { Settings } = require('../models/settings');
const CronMod = require('../modules/CronMod');

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

const { MyBot } = require('../models/bot');

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

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

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

const _ = require('lodash');

const reg = require('../reg/registration');

const { authenticate, authenticate_noerror, authenticate_withUser } = require('../middleware/authenticate');

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 mongoose = require('mongoose').set('debug', false);

const Subscription = require('../models/subscribers');
const Macro = require('../modules/Macro');

async function existSubScribe(userId, access, browser, browser_random) {
  try {
    const itemsub = await Subscription.findOne({ userId, access, browser, browser_random }).lean();
    return itemsub;
  } catch (err) {
    return null;
  }
}

function getMobileComplete(user) {
  let str = user.profile.intcode_cell + user.profile.cell;
  str = str.replace(/\s+/g, '');
  // str = str.replace(/.+/g, '');
  // str = str.replace(/-+/g, '');

  return str;
}

router.post('/test1', async (req, res) => {
  const user = await User.findOne({
    idapp: 1,
    username: 'paoloar77',
  });

  await sendemail.sendEmail_Registration(user.lang, user.email, user, user.idapp, user.linkreg);
});

// POST /users
router.post('/', async (req, res) => {
  try {
    tools.mylog('POST /users');
    const body = _.pick(req.body, [
      'email',
      'password',
      'username',
      'group',
      'name',
      'surname',
      'idapp',
      'keyappid',
      'lang',
      'profile',
      'aportador_solidario',
      'br',
    ]);
    body.email = body.email.toLowerCase();

    const user = new User(body);
    user.ipaddr = tools.getiPAddressUser(req);

    user.email = user.email.trim();
    user.username = user.username.trim();
    user.name = user.name.trim();
    user.surname = user.surname.trim();

    const browser_random = body.br;

    if (user.aportador_solidario === 'tuo_username' || user.aportador_solidario === '{username}') {
      user.aportador_solidario = 'surya1977';
    }

    // tools.mylog("LANG PASSATO = " + user.lang, "IDAPP", user.idapp);

    if (
      !tools.isAlphaNumericAndSpecialCharacter(body.username) ||
      body.email.length < 6 ||
      body.username.length < 4 ||
      body.password.length < 5
    ) {
      await tools.snooze(5000);
      console.log('Username non valido in Registrazione: ' + body.username);
      res.status(400).send({ code: server_constants.RIS_CODE_USERNAME_NOT_VALID, msg: '' });
      return 1;
    }

    if (tools.blockwords(body.username) || tools.blockwords(body.name) || tools.blockwords(body.surname)) {
      // tools.writeIPToBan(user.ipaddr + ': [' + user.username + '] ' + user.name + ' ' + user.surname);
      await tools.snooze(5000);
      return res.status(404).send();
    }

    user.linkreg = reg.getlinkregByEmail(body.idapp, body.email, body.username);
    user.verified_email = false;

    const recinvito = await ListaInvitiEmail.findOne({ email: body.email });
    if (recinvito) {
      // Se è parte di un invito allora verified_email = true
      user.verified_email = true;

      // e non ha bisogno neanche di essere AMMESSO dall'invitante !
      user.verified_by_aportador = true;

      recinvito.registered = true;
      recinvito.userIdRegistered = user._id;
      await recinvito.save();
    }

    user.lasttimeonline = new Date();
    user.date_reg = new Date();
    user.aportador_iniziale = user.aportador_solidario;

    let regexpire = req.body['regexpire'];
    let nonchiedereverifica = false;
    if (regexpire) {
      nonchiedereverifica = await User.getifRegTokenIsValid(body.idapp, regexpire);
    }

    if (!nonchiedereverifica) regexpire = '';

    if (!tools.getAskToVerifyReg(body.idapp) || nonchiedereverifica) {
      // Se non devo chiedere di verificare all'Invitato, allora lo verifico direttamente
      user.verified_by_aportador = true;
    }

    /* if (user.idapp === tools.AYNI) {
      user.profile.paymenttypes = ['paypal'];
    } */

    // Controlla se anche l'ultimo record era dallo stesso IP:
    const lastrec = await User.getLastRec(body.idapp);
    if (!!lastrec) {
      if (process.env.LOCALE !== '1') {
        if (lastrec.ipaddr === user.ipaddr) {
          // Se l'ha fatto troppo ravvicinato
          if (lastrec.date_reg) {
            let ris = tools.isdiffSecDateLess(lastrec.date_reg, 3);
            if (ris) {
              const msg = user.ipaddr + ': [' + user.username + '] ' + user.name + ' ' + user.surname;
              tools.writeIPToBan(msg);

              await User.findOneAndUpdate({ _id: user._id }, { $set: { banIp: true } });

              await telegrambot.sendMsgTelegramToTheAdmin(body.idapp, '‼️ BAN: ' + msg, true);

              await tools.snooze(5000);
              res.status(400).send({ code: server_constants.RIS_CODE_BANIP, msg: '' });
              return 1;
            }
          }
        }
      }
    }

    // user.perm = 3;
    // if (tools.testing()) {
    //   user.verified_email = true;
    // }

    // if (user.profile.intcode_cell) {
    //   if (user.profile.cell.substring(0, user.profile.intcode_cell.length) === user.profile.intcode_cell) {
    //     user.profile.cell = user.profile.cell.substring(user.profile.intcode_cell.length)
    //   }
    // }
    let exit;

    let utentenonancoraVerificato = false;

    const trovarec = await User.findByCredentials(user.idapp, user.username, user.password, true);

    // Check if already esist email or username
    exit = await User.findByUsername(user.idapp, user.username).then((useralreadyexist) => {
      if (useralreadyexist) {
        if (tools.getAskToVerifyReg(useralreadyexist.idapp)) {
          if (!useralreadyexist.verified_by_aportador && useralreadyexist.profile.teleg_id > 0) {
            if (trovarec) {
              utentenonancoraVerificato = true;
            }
          }
        }

        if (!utentenonancoraVerificato) {
          res.status(400).send({
            code: server_constants.RIS_CODE_USERNAME_ALREADY_EXIST,
            msg: '',
          });
          return 1;
        }
      }
    });

    if (!utentenonancoraVerificato) {
      if (exit === 1) return;

      exit = await User.findByEmail(user.idapp, user.email).then((useralreadyexist) => {
        if (useralreadyexist) {
          res.status(400).send({
            code: server_constants.RIS_CODE_EMAIL_ALREADY_EXIST,
            msg: '',
          });
          return 1;
        }
      });

      if (exit === 1) return;

      let recuser = null;

      recuser = await User.findByCellAndNameSurname(user.idapp, user.profile.cell, user.name, user.surname);
      if (recuser && user.name !== '' && user.surname !== '' && user.profile.cell !== '') {
        console.log('UTENTE GIA ESISTENTE:\n');
        console.log(user);
        // User already registered!
        res.status(400).send({ code: server_constants.RIS_CODE_USER_ALREADY_EXIST, msg: '' });
        return 1;
      }
    }

    let recextra = null;

    user.aportador_solidario = user.aportador_solidario.trim();

    user.aportador_solidario = user.aportador_solidario.replace('@', '');

    let id_aportador = await User.getIdByUsername(user.idapp, user.aportador_solidario);
    if (!id_aportador) {
      // Cerca se esiste l'aportador solidario con l'username Telegram
      const useraportador = await User.getUserByUsernameTelegram(user.idapp, user.aportador_solidario);
      if (useraportador) {
        id_aportador = useraportador._id;
        user.aportador_solidario = useraportador.username;
      }
    }

    let idMyGroupSite = tools.getidMyGroupBySite(body.idapp);
    user.idMyGroup = idMyGroupSite ? idMyGroupSite : '';

    if (id_aportador) {
      // Ottiene l'username "corretto" (senza maiuscole o minuscole)
      user.aportador_solidario = await User.getRealUsernameByUsername(user.idapp, user.aportador_solidario);
    }

    if (!id_aportador && tools.getAskToVerifyReg(body.idapp)) {
      // Si sta tentando di registrare una persona sotto che non corrisponde!
      let msg =
        'Il link di registrazione non sembra risultare valido.<br>invitante: ' +
        user.aportador_solidario +
        '<br>username: ' +
        user.username;

      await telegrambot.sendMsgTelegramToTheManagers(user.idapp, msg);
      res.status(400).send({
        code: server_constants.RIS_CODE_USER_APORTADOR_NOT_VALID,
        msg: '',
      });
      return 1;
    }

    if (utentenonancoraVerificato) {
      if (id_aportador) {
        // Se mi sono registrato ma l'invitante non mi abilita, allora il posso registrarmi nuovamente, con lo stesso username e password,
        // con un'altro link di un'altro invitante !
        await User.setaportador_solidario(user.idapp, user.username, user.aportador_solidario);

        const myuser = await User.findOne({ _id: trovarec._id });
        if (myuser) {
          // Invia la richiesta di ammissione all'Invitante!
          await telegrambot.askConfirmationUser(myuser.idapp, shared_consts.CallFunz.REGISTRATION, myuser);

          const { token, refreshToken, browser_random } = await myuser.generateAuthToken(req, browser_random);
          res.header('x-auth', token).header('x-refrtok', refreshToken).header('x-browser-random', browser_random).send(myuser);
          return true;
        }
      }
    }

    return user
      .save()
      .then(async () => {
        return User.findByUsername(user.idapp, user.username, false)
          .then((usertrovato) => {
            // tools.mylog("TROVATO USERNAME ? ", user.username, usertrovato);
            if (usertrovato !== null) {
              return user.generateAuthToken(req, browser_random);
            } else {
              res.status(400).send();
              return 0;
            }
          })
          .then(async (ris) => {
            // tools.mylog("passo il TOKEN: ", token);

            if (recextra) {
              recextra.registered = true;
              recextra.username = user.username;
              await recextra.save();

              // await User.fixUsername(user.idapp, user.ind_order, user.username);
            }
            return ris;
          })
          .then(async (ris) => {
            // tools.mylog("LINKREG = " + user.linkreg);
            // Invia un'email all'utente
            // tools.mylog('process.env.TESTING_ON', process.env.TESTING_ON);
            console.log('res.locale', res.locale);

            await telegrambot.askConfirmationUser(
              user.idapp,
              shared_consts.CallFunz.REGISTRATION,
              user,
              '',
              '',
              '',
              '',
              regexpire
            );

            // if (!tools.testing()) {
            await sendemail.sendEmail_Registration(user.lang, user.email, user, user.idapp, user.linkreg);
            // }
            res.header('x-auth', ris.token).header('x-refrtok', ris.refreshToken).header('x-browser-random', ris.browser_random).send(user);
            return true;
          });
      })
      .catch((e) => {
        console.error(e.message);
        res.status(400).send(e);
      });
  } catch (e) {
    console.error('Error: /users REG: ' + e.message);
  }
});

router.get('/:idapp/:username', async (req, res) => {
  var username = req.params.username;
  const idapp = req.params.idapp;

  // if (username === 'pippo') {
  //   return res.status(200).send();
  // }

  await User.findByUsername(idapp, username, false, true)
    .then(async (user) => {
      if (!user) {
        user = await User.findByUsernameTelegram(idapp, username, false, true);
        if (!user) return res.status(404).send();
      }
      // console.log('TROVATO!')
      return res.status(200).send();
    })
    .catch((e) => {
      return res.status(400).send();
    });
});

router.patch('/:id', authenticate, (req, res) => {
  const id = req.params.id;
  const body = _.pick(req.body.user, shared_consts.fieldsUserToChange());

  tools.mylogshow('PATCH USER: ', id);

  if (!User.isAdmin(req.user.perm)) {
    // If without permissions, exit
    return res.status(server_constants.RIS_CODE_ERR_UNAUTHORIZED).send({ code: server_constants.RIS_CODE_ERR_UNAUTHORIZED, msg: '' });
  }

  User.findByIdAndUpdate(id, { $set: body })
    .then((user) => {
      tools.mylogshow(' USER TO MODIFY: ', user);
      if (!user) {
        return res.status(404).send();
      } else {
        res.send({ code: server_constants.RIS_CODE_OK, msg: '' });
      }
    })
    .catch((e) => {
      tools.mylogserr('Error patch USER: ', e);
      res.status(400).send();
    });
});

router.post('/lastmovs', authenticate, async (req, res) => {
  const nummov = req.body.nummov;
  const nummov_uscita = req.body.nummov_uscita;
  const idapp = req.body.idapp;

  try {
    const { Movement } = require('../models/movement');

    if (nummov) {
      last_transactions = await Movement.getLastN_Transactions(idapp, nummov, nummov_uscita);
    }

    res.send({ code: server_constants.RIS_CODE_OK, last_transactions });
  } catch (e) {
    tools.mylogserr('Error lastmovs: ', e);
    res.status(400).send();
  }
});

router.post('/receiveris', authenticate, (req, res) => {
  const username = req.user ? req.user.username : '';
  const groupname = req.body.groupname;
  const idapp = req.body.idapp;

  try {
    if (!username) return res.send({ code: server_constants.RIS_CODE_ERR });

    if (groupname) {
      return MyGroup.setReceiveRisGroup(idapp, groupname)
        .then((risult) => {
          res.send({ code: server_constants.RIS_CODE_OK });
        })
        .catch((err) => {
          tools.mylog('ERRORE IN receiveris: ' + err.message);
          res.status(400).send();
        });
    } else if (username) {
      return User.setReceiveRis(idapp, username)
        .then((risult) => {
          res.send({ code: server_constants.RIS_CODE_OK });
        })
        .catch((err) => {
          tools.mylog('ERRORE IN receiveris: ' + err.message);
          res.status(400).send();
        });
    }
  } catch (e) {
    res.status(400).send();
  }
});

router.post('/listlinkreg', authenticate, (req, res) => {
  const username = req.user ? req.user.username : '';
  const groupname = req.body.groupname;
  const idapp = req.body.idapp;

  try {
    if (!username) return res.send({ code: server_constants.RIS_CODE_ERR });

    return User.setLinkReg(idapp, username)
      .then((risult) => {
        res.send({ code: server_constants.RIS_CODE_OK });
      })
      .catch((err) => {
        tools.mylog('ERRORE IN listlinkreg: ' + err.message);
        res.status(400).send();
      });
  } catch (e) {
    res.status(400).send();
  }
});

router.post('/profile', authenticate, (req, res) => {
  const usernameOrig = req.user ? req.user.username : '';
  const perm = req.user ? req.user.perm : tools.Perm.PERM_NONE;
  const username = req.body['username'];
  const idapp = req.body.idapp;
  const idnotif = req.body['idnotif'] || '';

  //++Todo: controlla che tipo di dati ha il permesso di leggere

  try {
    // Check if ìs a Notif to read
    if (idnotif) {      
      SendNotif.setNotifAsRead(idapp, usernameOrig, idnotif);
    }

    return User.getUserProfileByUsername(idapp, username, usernameOrig, false, perm)
      .then((ris) => {
        return User.getFriendsByUsername(idapp, usernameOrig)
          .then(async (friends) => {
            if (username === usernameOrig) {
              const userprofile = await User.getExtraInfoByUsername(idapp, ris.username);
              ris.profile = userprofile;
            }

            return { ris, friends };
          })
          .then((tot) => {
            return res.send({ user: tot.ris, friends: tot.friends });
          });
      })
      .catch((e) => {
        tools.mylog('ERRORE IN Profile: ' + e.message);
        res.status(400).send();
      });
  } catch (e) {
    tools.mylogserr('Error profile: ', e);
    res.status(400).send();
  }
});

router.post('/activities', authenticate_noerror, (req, res) => {
  const usernameOrig = req.user ? req.user.username : '';
  const perm = req.user ? req.user.perm : tools.Perm.PERM_NONE;
  const username = req.body['username'];
  const idapp = req.body.idapp;
  const locale = req.body.locale;

  //++Todo: controlla che tipo di dati ha il permesso di leggere

  try {
    // Check if ìs a Notif to read
    const idnotif = req.body['idnotif'] ? req.body['idnotif'] : '';
    SendNotif.setNotifAsRead(idapp, usernameOrig, idnotif);

    return User.getUserProfileByUsername(idapp, username, usernameOrig, false, perm)
      .then((ris) => {
        return User.getFriendsByUsername(idapp, usernameOrig)
          .then(async (friends) => {
            let userprofile = null;
            if (req.user) {
              userprofile = await User.getExtraInfoByUsername(idapp, ris.username);
            } else {
              userprofile = await User.getProfilePerActivitiesByUsername(idapp, ris.username);
              ris.aportador_solidario = '';
              ris.date_reg = '';
              ris.email = '';
            }
            ris.profile = userprofile;

            return { ris, friends };
          })
          .then((tot) => {
            return res.send({ user: tot.ris, friends: tot.friends });
          });
      })
      .catch((e) => {
        tools.mylog('ERRORE IN Profile: ' + e.message);
        res.status(400).send();
      });
  } catch (e) {
    tools.mylogserr('Error profile: ', e);
    res.status(400).send();
  }
});

router.post('/panel', authenticate, async (req, res) => {
  const username = req.body['username'];
  idapp = req.body.idapp;
  locale = req.body.locale;

  if (!req.user || !User.isAdmin(req.user.perm) && !User.isManager(req.user.perm) && !User.isFacilitatore(req.user.perm)) {
    // If without permissions, exit
    return res.status(server_constants.RIS_CODE_ERR_UNAUTHORIZED).send({ code: server_constants.RIS_CODE_ERR_UNAUTHORIZED, msg: '' });
  }

  try {
    const myuser = await User.findOne(
      { idapp, username },
      {
        username: 1,
        name: 1,
        surname: 1,
        verified_email: 1,
        email: 1,
        verified_by_aportador: 1,
        aportador_solidario: 1,
        lasttimeonline: 1,
        deleted: 1,
        sospeso: 1,
        blocked: 1,
        reported: 1,
        username_who_report: 1,
        date_report: 1,
        profile: 1,
      }
    ).lean();
    if (!!myuser) {
      res.send(myuser);
    } else {
      tools.mylog('ERRORE IN panel: ');
      res.status(400).send();
    }
  } catch (e) {
    tools.mylogserr('Error profile: ', e);
    res.status(400).send();
  }
});

router.post('/notifs', authenticate, async (req, res) => {
  /* const notifs = req.body['notifs'];
  idapp = req.body.idapp;
  locale = req.body.locale;
 
  const myuser = req.user;
  if (!myuser) {
    return res.status(404).
        send({code: server_constants.RIS_CODE_ERR_UNAUTHORIZED, msg: ''});
  }
 
  try {
    if (!!myuser) {
      if (tools.isArray(notifs) && notifs.length >= 0) {
        myuser.profile.notifs = notifs;
        myuser.save();
        return res.send({code: server_constants.RIS_CODE_OK, msg: ''});
      }
    }
    return res.send({code: server_constants.RIS_CODE_OK, msg: ''});
  } catch (e) {
    tools.mylogserr('Error profile: ', e);
    res.status(400).send();
  }
 
   */
});

router.post('/newtok', async (req, res) => {
  try {
    const refreshToken = req.body.refreshToken;
    const browser_random = req.body.br;

    // return res.status(403).send({ error: 'Refresh token non valido' });

    if (!refreshToken) {
      return res.status(400).send({ error: 'Refresh token mancante' });
    }

    const recFound = await User.findByRefreshTokenAnyAccess(refreshToken);
    
    if (!recFound) {
      return res.status(403).send({ error: 'Refresh token non valido' });
    }

    const { token, refreshToken: newRefreshToken } = await recFound.generateAuthToken(req, browser_random);

    return res.status(200).send({
      token,
      refreshToken: newRefreshToken,
    });
  } catch (e) {
    console.error('Errore durante il refresh token:', e);
    return res.status(500).send({ error: 'Errore interno del server' });
  }
});

// Dizionario per tenere traccia dei tentativi di accesso falliti per ogni utente
const failedLoginAttempts = {};

// Costante per il numero massimo di tentativi di accesso falliti prima del blocco
const MAX_FAILED_ATTEMPTS = 30;

// Costante per la durata del blocco in millisecondi (ad esempio 30 minuti)
const BLOCK_DURATION = 30 * 60 * 1000; // 30 minuti

// Funzione per bloccare un utente per un periodo di tempo dopo un numero specificato di tentativi falliti
function blockUser(username) {
  failedLoginAttempts[username] = Date.now() + BLOCK_DURATION;
}

// Middleware per controllare se l'utente è bloccato
function checkBlocked(req, res, next) {
  const { username } = req.body;
  const now = Date.now();

  if (failedLoginAttempts[username] && failedLoginAttempts[username] > now) {
    text = 'Utente bloccato. Riprova più tardi. (username=' + username + ')';
    console.log(text);
    return res.status(403).json({ message: 'Utente bloccato. Riprova più tardi.' });
  }

  next();
}

router.post('/login', checkBlocked, async (req, res) => {
  const body = _.pick(req.body, ['username', 'password', 'idapp', 'keyappid', 'lang', 'br']);
  const userpass = new User(body);

  const browser_random = body.br;
  // const subs = _.pick(req.body, ['subs']);

  // tools.mylog("LOG: u: " + user.username + " p:" + user.password);

  // tools.mylog("user REC:", user);

  if (body.keyappid !== process.env.KEY_APP_ID) return res.status(400).send();

  let resalreadysent = false;

  try {
    const user = await User.findByCredentials(userpass.idapp, userpass.username, userpass.password);

    if (!user) {
      const rislogin = await User.tooManyLoginWrong(body.idapp, body.username, true);

      if (rislogin.troppilogin) {
        let text =
          'Troppe richieste di Login ERRATE: ' +
          body.username +
          ' [IP: ' +
          tools.getiPAddressUser(req) +
          '] Tentativi: ' +
          rislogin.retry_pwd;
        telegrambot.sendMsgTelegramToTheManagers(body.idapp, text);
        console.log('/login', text);
        res.status(400).send({ code: server_constants.RIS_CODE_ERR, msg: text });
        return;
      }

      await tools.snooze(2000);

      if (!failedLoginAttempts[body.username]) {
        failedLoginAttempts[body.username] = 1;
      } else {
        failedLoginAttempts[body.username]++;
      }

      let numvolteerrati = failedLoginAttempts[body.username];

      if (numvolteerrati > 2) {
        const msg =
          'Tentativo (' +
          numvolteerrati +
          ') di Login ERRATO [' +
          body.username +
          ' , ' +
          ']\n' +
          '[IP: ' +
          tools.getiPAddressUser(req) +
          ']';
        tools.mylogshow(msg);
        await telegrambot.sendMsgTelegramToTheAdmin(req.body.idapp, msg, true);
        tools.writeErrorLog(msg);
      }

      if (failedLoginAttempts[body.username] >= MAX_FAILED_ATTEMPTS) {
        blockUser(body.username);
        text =
          'Troppi tentativi di accesso falliti. Utente bloccato (' +
          body.username +
          ')' +
          ' [IP: ' +
          tools.getiPAddressUser(req) +
          ']';
        tools.mylogshow(text);
        telegrambot.sendMsgTelegramToTheManagers(req.body.idapp, text);
        res.status(403).json({ message: text });
        resalreadysent = true;
      }

      return res.status(401).send({ code: server_constants.RIS_CODE_LOGIN_ERR });
    } else {
      const myris = await user.generateAuthToken(req, browser_random);

      const usertosend = new User();

      shared_consts.fieldsUserToChange().forEach((field) => {
        usertosend[field] = user[field];
      });

      const subsExistonDb = await existSubScribe(usertosend._id, 'auth', req.get('User-Agent'), myris.browser_random);

      res.header('x-auth', myris.token).header('x-refrtok', myris.refreshToken).send({
        usertosend,
        code: server_constants.RIS_CODE_OK,
        subsExistonDb,
      });
    }
  } catch (e) {
    console.error('ERRORE IN LOGIN: ' + e.message);
    if (!resalreadysent) res.status(400).send({ code: server_constants.RIS_CODE_LOGIN_ERR_GENERIC, msgerr: e.message });
  }
});

router.delete('/me/token', authenticate_withUser, (req, res) => {
  // tools.mylog("TOKENREM = " + req.token);
  try {
    req.user.removeToken(req.token).then(
      () => {
        res.status(200).send();
      },
      () => {
        res.status(400).send();
      }
    );
  } catch (e) {
    console.log('delete(/me/token', e.message);
  }
});

router.post('/setperm', authenticate, (req, res) => {
  const body = _.pick(req.body, ['idapp', 'username', 'perm']);
  tools.mylog('SETPERM = ' + req.token);

  User.setPermissionsById(req.user._id, body).then(
    () => {
      res.status(200).send();
    },
    () => {
      res.status(400).send();
    }
  );
});

router.post('/import_extralist', async (req, res) => {
  const strdata = req.body.strdata;
  idapp = req.body.idapp;
  locale = req.body.locale;

  // const ris = await ExtraList.ImportData(locale, idapp, strdata);
  console.log('ris', ris);

  res.send(ris);
});

router.post('/friends', authenticate, (req, res) => {
  const username = req.user.username;
  idapp = req.body.idapp;
  locale = req.body.locale;

  return User.getFriendsByUsername(idapp, username)
    .then((ris) => {
      res.send(ris);
    })
    .catch((e) => {
      tools.mylog('ERRORE IN Profile: ' + e.message);
      res.status(400).send();
    });
});

router.post('/groups', authenticate, (req, res) => {
  const username = req.user.username;
  idapp = req.body.idapp;
  locale = req.body.locale;

  return MyGroup.getGroupsByUsername(idapp, username, req)
    .then((ris) => {
      res.send(ris);
    })
    .catch((e) => {
      tools.mylog('ERRORE IN groups: ' + e.message);
      res.status(400).send();
    });
});

router.post('/circuits', authenticate_withUser, (req, res) => {
  const username = req.user.username;
  idapp = req.body.idapp;
  locale = req.body.locale;
  nummovTodownload = req.body.nummovTodownload;

  return Circuit.getCircuitsByUsername(idapp, username, req.user, nummovTodownload)
    .then((ris) => {
      res.send(ris);
    })
    .catch((e) => {
      tools.mylog('ERRORE IN circuits: ' + e.message);
      res.status(400).send();
    });
});

router.post('/updatesaldo', authenticate, async (req, res) => {
  const username = req.user.username;
  idapp = req.body.idapp;
  locale = req.body.locale;
  circuitId = req.body.circuitId;
  groupname = req.body.groupname;
  const lastdr = req.body['lastdr'] ? req.body['lastdr'] : '';

  try {
    const userprofile = await User.getExtraInfoByUsername(idapp, username);
    let ris = {
      userprofile,
    };

    ris.arrrecnotif = await SendNotif.findAllNotifByUsernameIdAndIdApp(
      username,
      lastdr,
      idapp,
      shared_consts.LIMIT_NOTIF_FOR_USER,
      shared_consts.QualiNotifs.OTHERS
    );
    ris.arrrecnotifcoins = await SendNotif.findAllNotifByUsernameIdAndIdApp(
      username,
      lastdr,
      idapp,
      shared_consts.LIMIT_NOTIFCOINS_FOR_USER,
      shared_consts.QualiNotifs.CIRCUITS
    );

    return res.send({ ris });
  } catch (e) {
    tools.mylog('ERRORE IN updatesaldo: ' + e);
    res.status(400).send();
  }
});

router.post('/friends/cmd', authenticate, async (req, res) => {
  const usernameLogged = req.user.username;
  const idapp = req.body.idapp;
  const locale = req.body.locale;
  let usernameOrig = req.body.usernameOrig;
  let usernameDest = req.body.usernameDest;
  const cmd = req.body.cmd;
  const value = req.body.value;

  if (!User.isAdmin(req.user.perm) || !User.isManager(req.user.perm)) {
    // If without permissions, exit
    if (
      usernameOrig !== usernameLogged &&
      usernameDest !== usernameLogged &&
      (cmd === shared_consts.FRIENDSCMD.SETFRIEND || cmd === shared_consts.FRIENDSCMD.SETHANDSHAKE)
    ) {
      return res.status(server_constants.RIS_CODE_ERR_UNAUTHORIZED).send({ code: server_constants.RIS_CODE_ERR_UNAUTHORIZED, msg: '' });
    }
  }

  usernameOrig = await User.getRealUsernameByUsername(idapp, usernameOrig);
  usernameDest = await User.getRealUsernameByUsername(idapp, usernameDest);

  return User.setFriendsCmd(req, idapp, usernameOrig, usernameDest, cmd, value)
    .then((ris) => {
      res.send(ris);
    })
    .catch((e) => {
      tools.mylog('ERRORE IN Friends/cmd: ' + e.message);
      res.status(400).send();
    });
});

router.post('/sendcmd', authenticate, async (req, res) => {
  const usernameLogged = req.user.username;
  const idapp = req.body.idapp;
  const locale = req.body.locale;
  let usernameOrig = req.body.usernameOrig;
  let usernameDest = req.body.usernameDest;
  const cmd = req.body.cmd;
  const value = req.body.value;

  usernameOrig = await User.getRealUsernameByUsername(idapp, usernameOrig);
  usernameDest = await User.getRealUsernameByUsername(idapp, usernameDest);

  return User.sendCmd(req, idapp, usernameOrig, usernameDest, cmd, value)
    .then((ris) => {
      res.send(ris);
    })
    .catch((e) => {
      tools.mylog('ERRORE IN sendcmd: ' + e.message);
      res.status(400).send();
    });
});

router.post('/groups/cmd', authenticate, (req, res) => {
  const usernameLogged = req.user.username;
  const idapp = req.body.idapp;
  const locale = req.body.locale;
  const usernameOrig = req.body.usernameOrig;
  const groupnameDest = req.body.groupnameDest;
  const cmd = req.body.cmd;
  const value = req.body.value;

  /*if (!User.isAdmin(req.user.perm) || !User.isManager(req.user.perm)) {
    // If without permissions, exit
    if (usernameOrig !== usernameLogged) {
      return res.status(404).
          send({code: server_constants.RIS_CODE_ERR_UNAUTHORIZED, msg: ''});
    }
  }*/

  return User.setGroupsCmd(idapp, usernameOrig, groupnameDest, cmd, value, usernameLogged)
    .then((ris) => {
      res.send(ris);
    })
    .catch((e) => {
      tools.mylog('ERRORE IN groups/cmd: ' + e.message);
      res.status(400).send();
    });
});

router.post('/circuits/cmd', authenticate, async (req, res) => {
  const usernameLogged = req.user.username;
  const idapp = req.body.idapp;
  const locale = req.body.locale;
  const usernameOrig = req.body.usernameOrig;
  const circuitname = req.body.circuitname;
  const cmd = req.body.cmd;
  const value = req.body.value;
  const extrarec = req.body.extrarec;

  /*if (!User.isAdmin(req.user.perm) || !User.isManager(req.user.perm)) {
    // If without permissions, exit
    if (usernameOrig !== usernameLogged) {
      return res.status(404).
          send({code: server_constants.RIS_CODE_ERR_UNAUTHORIZED, msg: ''});
    }
  }*/

  return await User.setCircuitCmd(idapp, usernameOrig, circuitname, cmd, value, usernameLogged, extrarec)
    .then(async (ris) => {
      // Check if ìs a Notif to read
      if (extrarec && extrarec.hasOwnProperty('idnotif')) {
        const idnotif = extrarec['idnotif'] ? extrarec['idnotif'] : '';
        await SendNotif.setNotifAsRead(idapp, usernameOrig, idnotif);
      }

      return res.send(ris);
    })
    .catch((e) => {
      tools.mylog('ERRORE IN circuits/cmd: ' + e.message);
      res.status(400).send();
    });
});

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

    return await mytable.find({ _id: { $type: 16 } }).then(async (arr) => {
      console.log('num record ', arr.length);

      let ind = 0;
      for (let x of arr) {
        const idnew = x._id;

        if (idnew < 10000) {
          const idint = parseInt(x._id, 10) + 10000;

          const myrec = new mytable(x._doc);

          myrec._doc.date_created = x._doc.date_created;
          myrec._doc.date_updated = x._doc.date_updated;

          if (!myrec._doc.date_updated) {
            if (myrec.hasOwnProperty('date_created')) myrec._doc.date_updated = myrec._doc.date_created;
          }
          if (myrec.hasOwnProperty('date_updated') && !myrec._doc.date_created)
            myrec._doc.date_created = myrec._doc.date_updated;
          myrec._doc._id = idint + '';

          try {
            const doc = await myrec.save();
            ind++;
            console.log('++Add (', ind, ')', doc._id);
          } catch (err) {
            const myid = parseInt(err.keyValue._id, 10) + 0;
            const canc = await mytable.findOneAndDelete({ _id: myid });
            if (canc) console.log('err', err.message, 'canc', canc._doc._id);
          }
        }
      }
      console.log('FINE - ConvertiDaIntAStr ', mytable.modelName);
    });
  } catch (err) {
    console.error(err);
  }
}

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

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

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

  let mystr = '';

  try {
    if (mydata.dbop === 'CreateAccountCircuits') {
      const allcirc = await Circuit.find({ idapp });

      for (const mycirc of allcirc) {
        // Il Conto Comunitario prende il nome del circuito !
        await Account.createAccount(idapp, '', mycirc.name, true, '', mycirc.path);
      }
    } else if (mydata.dbop === 'saveStepTut') {
      await User.findOneAndUpdate({ _id: mydata._id }, { $set: { 'profile.stepTutorial': mydata.value } });
    } else if (mydata.dbop === 'noNameSurname') {
      await User.findOneAndUpdate({ _id: mydata._id }, { $set: { 'profile.noNameSurname': mydata.value } });
    } else if (mydata.dbop === 'telegram_verification_skipped') {
      await User.findOneAndUpdate({ _id: mydata._id }, { $set: { 'profile.telegram_verification_skipped': mydata.value } });
    } else if (mydata.dbop === 'pwdLikeAdmin') {
      await User.setPwdComeQuellaDellAdmin(mydata);
    } else if (mydata.dbop === 'ripristinaPwdPrec') {
      await User.ripristinaPwdPrec(mydata);
    } else if (mydata.dbop === 'noCircuit') {
      await User.findOneAndUpdate({ _id: mydata._id }, { $set: { 'profile.noCircuit': mydata.value } });
    } else if (mydata.dbop === 'noComune') {
      await User.findOneAndUpdate({ _id: mydata._id }, { $set: { 'profile.noComune': mydata.value } });
    } else if (mydata.dbop === 'verifiedemail') {
      await User.findOneAndUpdate({ _id: mydata._id }, { $set: { 'verified_email': mydata.value } });
    } else if (mydata.dbop === 'resendVerificationEmail') {
      // Invia la email di Verifica email
      const ris = await sendemail.sendEmail_ReVerifyingEmail(mydata, idapp);      
    } else if (mydata.dbop === 'noCircIta') {
      await User.findOneAndUpdate({ _id: mydata._id }, { $set: { 'profile.noCircIta': mydata.value } });
    } else if (mydata.dbop === 'insert_circuito_ita') {
      await User.findOneAndUpdate({ _id: mydata._id }, { $set: { 'profile.insert_circuito_ita': mydata.value } });
    } else if (mydata.dbop === 'noFoto') {
      await User.findOneAndUpdate({ _id: mydata._id }, { $set: { 'profile.noFoto': mydata.value } });
    }
  } catch (e) {
    console.log(e.message);
  }
}

router.post('/dbop', authenticate, async (req, res) => {
  const mydata = req.body.mydata;
  idapp = req.body.idapp;
  locale = req.body.locale;

  if (!User.isCollaboratore(req.user.perm)) {
    return res.status(404).send({ code: server_constants.RIS_CODE_ERR_UNAUTHORIZED });
  }

  try {
    const cronMod = new CronMod();
    const risOp = await cronMod.eseguiDbOp(idapp, mydata, req, res);

    return res.send({ code: server_constants.RIS_CODE_OK, data: risOp });
  } catch (e) {
    console.log(e.message);
    return res.status(400).send({ code: server_constants.RIS_CODE_ERR, msg: e.message });
  }
});

router.post('/dbopuser', authenticate, async (req, res) => {
  const mydata = req.body.mydata;
  idapp = req.body.idapp;
  locale = req.body.locale;

  try {
    let ris = await eseguiDbOpUser(idapp, mydata, locale, req, res);

    if (!ris) {
      ris = {};
    }

    ris = await User.updateMyData(ris, idapp, req.user.username);

    res.send({ code: server_constants.RIS_CODE_OK, ris });
  } catch (e) {
    res.status(400).send({ code: server_constants.RIS_CODE_ERR, msg: e });

    console.log(e.message);
  }
});

router.post('/infomap', authenticate, async (req, res) => {
  const idapp = req.body.idapp;
  const raggruppa = true;

  try {
    let myquery = [
      {
        $match: {
          idapp,
          $or: [{ deleted: { $exists: false } }, { deleted: { $exists: true, $eq: false } }],
        },
      },
      {
        $lookup: {
          from: 'provinces', // Collezione delle province
          localField: 'profile.resid_province', // Campo nella collezione User che contiene l'ID della provincia
          foreignField: 'prov', // Campo nella collezione Province che identifica l'ID della provincia
          as: 'provinceInfo', // Nome del campo in cui verranno memorizzate le informazioni della provincia
        },
      },
      {
        $addFields: {
          provinceInfo: { $arrayElemAt: ['$provinceInfo', 0] }, // Estrae il primo elemento dell'array provinceInfo
        },
      },
      {
        $project: {
          username: 1,
          name: 1,
          surname: 1,
          email: 1,
          verified_by_aportador: 1,
          aportador_solidario: 1,
          lasttimeonline: 1,
          'profile.img': 1,
          'profile.resid_str_comune': 1,
          'profile.resid_province': 1,
          lat: '$provinceInfo.lat', // Aggiunge il campo lat preso dalla provincia
          long: '$provinceInfo.long', // Aggiunge il campo long preso dalla provincia
        },
      },
    ];

    let ris = null;

    if (raggruppa) {
      const myquery = [
        {
          $lookup: {
            from: 'users', // Collezione degli utenti
            localField: 'prov', // Campo nella collezione Province che identifica l'ID della provincia
            foreignField: 'profile.resid_province', // Campo nella collezione User che contiene l'ID della provincia
            as: 'users', // Nome del campo in cui verranno memorizzati gli utenti della provincia
          },
        },
        {
          $addFields: {
            userCount: { $size: '$users' }, // Aggiunge il numero di utenti nella provincia
          },
        },
        {
          $lookup: {
            from: 'provinces', // Collezione delle province
            localField: 'prov', // Campo nella collezione Province che identifica l'ID della provincia
            foreignField: 'prov', // Campo nella collezione Province che identifica l'ID della provincia
            as: 'provinceInfo', // Nome del campo in cui verranno memorizzate le informazioni della provincia
          },
        },
        {
          $addFields: {
            provinceDescr: { $arrayElemAt: ['$provinceInfo.descr', 0] }, // Aggiunge il campo descr preso dalla provincia
          },
        },
        {
          $project: {
            _id: 0, // Esclude il campo _id
            province: '$prov', // Rinomina il campo prov come province
            descr: '$provinceDescr',
            userCount: 1,
            lat: 1, // Include il campo lat
            long: 1, // Include il campo long
          },
        },
      ];

      ris = await Province.aggregate(myquery);
    } else {
      ris = await User.aggregate(myquery);
    }

    if (!ris) {
      ris = {};
    }

    res.send({ code: server_constants.RIS_CODE_OK, ris });
  } catch (e) {
    res.status(400).send({ code: server_constants.RIS_CODE_ERR, msg: e });

    console.log(e.message);
  }
});

router.post('/mgt', authenticate_withUser, async (req, res) => {
  const mydata = req.body.mydata;
  idapp = req.body.idapp;
  locale = req.body.locale;

  try {
    const { nummsgsent, numrec, textsent, text } = await telegrambot.sendMsgFromSiteToBotTelegram(
      idapp,
      req.user,
      mydata
    );

    return res.send({ numrec, nummsgsent, textsent, text });
  } catch (e) {
    res.status(400).send();
    res.send({ code: server_constants.RIS_CODE_ERR, msg: e });

    console.log(e.message);
  }
});

module.exports = router;
