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

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

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

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

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

const { Province } = require('../models/province');
const shared_consts = require('../tools/shared_nodejs');

const i18n = require('i18n');

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

const CircuitSchema = new Schema({
  _id: {
    type: String,
    default: function () {
      return new ObjectId().toString();
    },
  },
  idapp: {
    type: String,
    required: true,
  },
  groupnameId: {
    type: String,
  },
  name: {
    type: String,
    unique: true,
  },
  path: {
    type: String,
    unique: true,
  },
  link_group: {
    type: String,
  },
  subname: {
    type: String,
  },
  idCity: [
    {
      type: Number,
    },
  ],
  strProv: {
    type: String,
  },
  // Punti cardinali
  card: {
    type: String,
  },
  pub_to_share: {
    type: Number, // PUB_TO_SHARE_ALL, PUB_TO_SHARE_ONLY_TABLE_FOLLOW
  },
  visibility: [
    {
      type: Number,
    },
  ],
  longdescr: {
    type: String,
  },
  regulation: {
    type: String,
  },
  systemUserDescr: {
    type: String,
  },
  systemUserId: {
    type: String,
  },
  totCircolante: {
    type: Number,
  },
  totTransato: {
    type: Number,
  },
  numTransazioni: {
    type: Number,
  },
  nome_valuta: {
    type: String,
    maxlength: 20,
  },
  symbol: {
    type: String,
    maxlength: 7,
  },
  color: {
    type: String,
  },
  abbrev: {
    type: String,
    maxlength: 7,
  },
  compara_valuta: {
    type: Number,
    default: 1,
  },
  compara_euro: {
    type: Number,
    default: 1,
  },
  valuta_per_euro: {
    type: Number,
    default: 1,
  },
  fido_scoperto_default: {
    type: Number,
  },
  qta_max_default: {
    type: Number,
  },
  fido_scoperto_default_grp: {
    type: Number,
  },
  qta_max_default_grp: {
    type: Number,
  },
  fido_scoperto_default_contocom: {
    type: Number,
  },
  qta_max_default_contocom: {
    type: Number,
  },
  data_costituz: {
    type: Date,
  },
  deperimento: {
    type: Boolean,
  },
  freq_deper: {
    // H, D, W, M, Y
    type: String,
  },
  minuto_deper: {
    type: Number,
  },
  ora_deper: {
    type: Number,
  },
  giorno_deper: {
    type: Number,
  },
  mese_deper: {
    type: Number,
  },
  ultimo_deper: {
    type: Date,
  },
  durata_deper: {
    type: Number,
  },
  // -------------
  createdBy: {
    type: String,
  },
  date_created: {
    type: Date,
    default: Date.now,
  },
  date_updated: {
    type: Date,
  },
  admins: [
    {
      username: { type: String },
      date: { type: Date },
      enable_to_receive_email: { type: Boolean },
    },
  ],
  photos: [
    {
      imagefile: {
        type: String,
      },
      alt: {
        type: String,
      },
      description: {
        type: String,
      },
    },
  ],
  req_users: [
    {
      _id: false,
      username: { type: String },
      date: { type: Date },
    },
  ], // username
  refused_users: [
    {
      _id: false,
      username: { type: String },
      date: { type: Date },
    },
  ], // username
  req_groups: [
    {
      _id: false,
      groupname: { type: String },
      date: { type: Date },
    },
  ], // username
  refused_groups: [
    {
      _id: false,
      groupname: { type: String },
      date: { type: Date },
    },
  ], // username
  deleted: {
    type: Boolean,
    default: false,
  },
  transactionsEnabled: {
    type: Boolean,
  },
  numMembers: {
    type: Number,
    default: 0,
  },
  circuitiExtraProv: {
    type: Boolean,
    default: false,
  },
  isCircItalia: {
    type: Boolean,
  },
  enableOnlyIf1CircuitExist: {
    type: Boolean,
  },
  status: {
    type: Number,
    default: 0,
  },
  ignoreLimits: {
    type: Boolean,
    default: false,
  },
  askManagerToEnter: {
    type: Boolean,
    default: false,
  },
  sendEmailAfterAskingToEnter: {
    type: Boolean,
    default: false,
  },
  circuitoIndipendente: {
    type: Boolean,
    default: false,
  },
  creditodiPartenza: {
    type: Number,
    default: 0,
  },
});

CircuitSchema.pre('save', async function (next) {
  if (this.isNew) {
    this._id = new ObjectId().toString();

    this.date_created = new Date();
  }

  next();
});

CircuitSchema.statics.findAllIdApp = async function (idapp) {
  const Circuit = this;

  const myfind = { idapp, deleted: false };

  const whatToShow = this.getWhatToShow(idapp, '');

  return await Circuit.find(myfind, whatToShow).sort({ name: 1 }).lean();
};

CircuitSchema.statics.isCircuitAdmin = async function (idrec, username) {
  const Circuit = this;

  const mycirc = await Circuit.findOne({ _id: idrec }).lean();
  if (mycirc) {
    return mycirc.admins.some(
      (admin) => admin.username === username || shared_consts.USER_ADMIN_CIRCUITS.includes(admin.username)
    );
  }

  return false;
};

CircuitSchema.statics.getFieldsForSearch = function () {
  return [
    { field: 'name', type: tools.FieldType.string },
    { field: 'subname', type: tools.FieldType.string },
    { field: 'path', type: tools.FieldType.string },
    { field: 'nome_valuta', type: tools.FieldType.string },
    { field: 'descr', type: tools.FieldType.string },
  ];
};

CircuitSchema.statics.executeQueryTable = function (idapp, params, user) {
  params.fieldsearch = this.getFieldsForSearch();
  return tools.executeQueryTable(this, idapp, params, user);
};

CircuitSchema.statics.getWhatToShow = function (idapp, username) {
  // FOR ME, PERMIT ALL
  return {
    _id: 1,
    groupnameId: 1,
    path: 1,
    name: 1,
    subname: 1,
    longdescr: 1,
    regulation: 1,
    numMembers: 1,
    totCircolante: 1,
    totTransato: 1,
    numTransazioni: 1,
    systemUserId: 1,
    createdBy: 1,
    date_created: 1,
    date_updated: 1,
    nome_valuta: 1,
    fido_scoperto_default: 1,
    qta_max_default: 1,
    fido_scoperto_default_grp: 1,
    qta_max_default_grp: 1,
    fido_scoperto_default_contocom: 1,
    qta_max_default_contocom: 1,
    deperimento: 1,
    circuitiExtraProv: 1,
    isCircItalia: 1,
    enableOnlyIf1CircuitExist: 1,
    ignoreLimits: 1,
    askManagerToEnter: 1,
    sendEmailAfterAskingToEnter: 1,
    circuitoIndipendente: 1,
    creditodiPartenza: 1,
    transactionsEnabled: 1,
    status: 1,
    valuta_per_euro: 1,
    symbol: 1,
    idCity: 1,
    strProv: 1,
    card: 1,
    link_group: 1,
    pub_to_share: 1,
    visibility: 1,
    color: 1,
    abbrev: 1,
    data_costituz: 1,
    photos: 1,
    admins: 1,
    req_users: 1,
    refused_users: 1,
    req_groups: 1,
    refused_groups: 1,
    mycities: 1,
  };
};

// Aggiungi agli Admin del Circuito
CircuitSchema.statics.addToAdminOfMyCircuit = async function (idapp, username, name) {
  return await Circuit.updateOne(
    { idapp, name },
    {
      $push: {
        admins: {
          username,
          date: new Date(),
        },
      },
    }
  );
};

// Rimuovi dagli Admin del Circuito
CircuitSchema.statics.removeAdminOfMyCircuit = async function (idapp, username, name) {
  return await Circuit.updateOne({ idapp, name }, { $pull: { admins: { username: { $in: [username] } } } });
};

CircuitSchema.statics.getWhatToShow_Unknown = function (idapp, username) {
  return {
    groupnameId: 1,
    path: 1,
    name: 1,
    subname: 1,
    longdescr: 1,
    regulation: 1,
    numMembers: 1,
    circuitiExtraProv: 1,
    isCircItalia: 1,
    enableOnlyIf1CircuitExist: 1,
    ignoreLimits: 1,
    askManagerToEnter: 1,
    sendEmailAfterAskingToEnter: 1,
    circuitoIndipendente: 1,
    creditodiPartenza: 1,
    systemUserId: 1,
    founderUserId: 1,
    nome_valuta: 1,
    totCircolante: 1,
    totTransato: 1,
    numTransazioni: 1,
    fido_scoperto_default: 1,
    fido_scoperto_default_grp: 1,
    qta_max_default_grp: 1,
    fido_scoperto_default_contocom: 1,
    qta_max_default_contocom: 1,
    qta_max_default: 1,
    valuta_per_euro: 1,
    symbol: 1,
    color: 1,
    idCity: 1,
    strProv: 1,
    card: 1,
    link_group: 1,
    pub_to_share: 1,
    visibility: 1,
    abbrev: 1,
    data_costituz: 1,
    photos: 1,
    admins: 1,
    createdBy: 1,
    date_created: 1,
    date_updated: 1,
    req_users: 1,
    refused_users: 1,
    req_groups: 1,
    refused_groups: 1,
    transactionsEnabled: 1,
    status: 1,
    mycities: 1,
  };
};

CircuitSchema.statics.getCircuitsByUsername = async function (idapp, username, user, nummovTodownload) {
  try {
    const { User } = require('../models/user');
    const { Account } = require('../models/account');

    const whatToShow = this.getWhatToShow(idapp, username);
    const whatToShow_Unknown = this.getWhatToShow_Unknown(idapp, username);
    // const arrUsernameCircuits = await User.getUsernameCircuitsByUsername(idapp, username);
    // const arrUsernameReqCircuits = await MyCircuit.getUsernameReqCircuitsByCircuitname(idapp, username);

    const manage_mycircuits = await Circuit.find({
      idapp,
      admins: {
        $elemMatch: { username: { $eq: username } },
      },
      $or: [{ deleted: { $exists: false } }, { deleted: { $exists: true, $eq: false } }],
    })
      .sort({ status: -1, numMembers: -1, name: 1 })
      .lean();

    let listcircuits = await Circuit.find(
      {
        idapp,
        $or: [{ deleted: { $exists: false } }, { deleted: { $exists: true, $eq: false } }],
      },
      whatToShow_Unknown
    )
      .sort({ name: 1 })
      .lean();

    let asked_circuits = await Circuit.find(
      {
        idapp,
        req_users: {
          $elemMatch: { username: { $eq: username } },
        },
        $or: [{ deleted: { $exists: false } }, { deleted: { $exists: true, $eq: false } }],
      },
      whatToShow_Unknown
    )
      .sort({ status: -1 })
      .lean();

    let refused_circuits = await Circuit.find(
      {
        idapp,
        refused_users: {
          $elemMatch: { username: { $eq: username } },
        },
        $or: [{ deleted: { $exists: false } }, { deleted: { $exists: true, $eq: false } }],
      },
      whatToShow_Unknown
    )
      .sort({ status: -1 })
      .lean();

    const last_my_transactions = await Movement.getLastN_Transactions(
      idapp,
      nummovTodownload,
      nummovTodownload,
      username,
      ''
    );
    const total_transactions = await Movement.getNumTotalTransactions(idapp, username, '');

    return {
      listcircuits,
      asked_circuits,
      refused_circuits,
      manage_mycircuits,
      mycircuits: user.profile.mycircuits,
      last_my_transactions,
      total_transactions,
    };
  } catch (e) {
    console.log('Error getCircuitsByUsername', e);
  }

  return {
    listUsersCircuit: [],
    listRequestUsersCircuit: [],
    listTrusted: [],
    asked_circuits: [],
    refused_circuits: [],
  };
};

CircuitSchema.statics.getInfoCircuitByName = async function (idapp, name) {
  const whatToShow = this.getWhatToShow(idapp, '');

  const myfind = {
    idapp,
    name,
  };

  try {
    return await Circuit.findOne(myfind, whatToShow).lean();
  } catch (e) {
    return null;
  }
};

CircuitSchema.statics.getCircuitByName = async function (idapp, name) {
  if (name === 'Circuito RIS Benevento') {
    name = 'Circuito RIS Campania';
  } else if (name === 'RIS Pesaro e Urbino') {
    name = 'Circuito RIS Pesaro e Urbino';
  } else if (name === 'RIS Catania') {
    name = 'Circuito RIS Catania';
  } else if (name === 'RIS Palermo') {
    name = 'Circuito RIS Palermo';
  }

  const myfind = {
    idapp,
    name,
  };

  try {
    return await Circuit.findOne(myfind);
  } catch (e) {
    return null;
  }
};

CircuitSchema.statics.getCircuitIdByName = async function (idapp, name) {
  const myfind = {
    idapp,
    name,
  };

  try {
    const circuit = await Circuit.findOne(myfind);
    return !!circuit ? circuit._id : 0;
  } catch (e) {
    return null;
  }
};

CircuitSchema.statics.getCircuitByProvinceAndCard = async function (idapp, strProv, card) {
  let myfind = {};

  if (card) {
    myfind = {
      idapp,
      strProv,
      card,
    };
  } else {
    myfind = {
      idapp,
      strProv,
    };
  }

  try {
    return await Circuit.findOne(myfind);
  } catch (e) {
    return null;
  }
};

CircuitSchema.statics.getCircuitById = async function (circuitId) {
  const myfind = {
    _id: circuitId,
  };

  try {
    return await Circuit.findOne(myfind);
  } catch (e) {
    return null;
  }
};

CircuitSchema.statics.deleteCircuit = async function (idapp, usernameOrig, name) {
  console.log('Circuito ' + name + ' rimosso da ' + usernameOrig);
  return await Circuit.findOneAndDelete({ idapp, name });
};

CircuitSchema.statics.getUsersSingleCircuit = async function (idapp, username, circuitname, circuitId) {
  const { User } = require('../models/user');

  try {
    let aggr1 = [
      {
        $match: {
          idapp: idapp,
          'profile.mycircuits': {
            $elemMatch: { circuitname: { $eq: circuitname } },
          },
        },
      },

      /*{
        $lookup: {
          from: 'circuits',
          as: 'circuit',
          let: {circuitname: circuitname, idapp: '$idapp'},
          pipeline: [
            {
              $match:
                  {
                    $expr:
                        {
                          $and:
                              [
                                {$eq: ['$name', '$$circuitname']},
                                {$eq: ['$idapp', '$$idapp']},

                              ],
                        },
                  },
            },
          ],
        },

      },
      {$unwind: '$circuit'},
       */
      {
        $project: {
          username: 1,
          verified_by_aportador: 1,
          name: 1,
          surname: 1,
          profile: 1,
          idapp: 1 /*, 'circuit.name': 1, 'circuit._id': 1*/,
        },
      },
      {
        $lookup: {
          from: 'accounts',
          as: 'account',
          let: { username: '$username', idapp: '$idapp', circuitId: circuitId /*, circuitId: '$circuit._id' */ },
          pipeline: [
            {
              $match: {
                $expr: {
                  $and: [
                    { $eq: ['$$username', '$username'] },
                    { $eq: ['$$idapp', '$idapp'] },
                    { $eq: ['$$circuitId', '$circuitId'] },
                  ],
                },
              },
            },
          ],
        },
      },
      { $unwind: '$account' },
    ];

    ris = await User.aggregate(aggr1);

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

CircuitSchema.statics.getCircolanteSingolaTransaz = function (accountorigTable, accountdestTable) {
  let circolante = 0;
  if (accountdestTable.saldo > 0) circolante += accountdestTable.saldo;
  if (accountorigTable.saldo > 0) circolante += accountorigTable.saldo;

  return circolante;
};

CircuitSchema.statics.sendCoins = async function (onlycheck, idapp, usernameOrig, extrarec) {
  const { User } = require('../models/user');

  const { MyGroup } = require('./mygroup');

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

  let ris = {
    result: false,
    cansend: true,
    errorcode: 0,
    errormsg: '',
    rec: null,
    useraccounts: [],
  };

  try {
    let circuittable = null;
    if (extrarec.circuitname) circuittable = await Circuit.getCircuitByName(idapp, extrarec.circuitname);
    if (extrarec.circuitId) circuittable = await Circuit.getCircuitById(idapp, extrarec.circuitId);

    if (circuittable) {
      const myqty = Math.abs(extrarec.qty);

      const esisteDest = await Account.isExistAccountByUsernameAndCircuitId(
        idapp,
        extrarec.dest,
        circuittable._id,
        extrarec.groupdest,
        extrarec.contoComDest
      );

      if (!esisteDest) {
        // Fallo entrare anche sul Circuito (oltre ad aver creato l'Account).
        await User.addCircuitToUser(
          idapp,
          usernameOrig,
          extrarec.circuitname,
          false,
          extrarec.groupdest,
          extrarec.contoComDest
        );
      }
      if (extrarec.dest) {
        const foundIfAlreadyCircuit = await User.ifAlreadyInCircuit(idapp, extrarec.dest, extrarec.circuitname);
        if (!foundIfAlreadyCircuit) {
          update = {
            $push: {
              'profile.mycircuits': {
                circuitname: extrarec.circuitname,
                date: new Date(),
              },
            },
          };
          const ris = await User.updateOne({ idapp, username: extrarec.dest }, update);
        }
      }

      const accountdestTable = await Account.getAccountByUsernameAndCircuitId(
        idapp,
        extrarec.dest,
        circuittable._id,
        true,
        false,
        extrarec.groupdest,
        extrarec.contoComDest
      );
      const accountorigTable = await Account.getAccountByUsernameAndCircuitId(
        idapp,
        usernameOrig,
        circuittable._id,
        true,
        true,
        extrarec.grouporig,
        extrarec.contoComOrig
      );

      const circolantePrec = this.getCircolanteSingolaTransaz(accountorigTable, accountdestTable);

      if (!circuittable.ignoreLimits) {
        // Check if Sender has enough money
        if (accountorigTable.saldo - myqty < -accountorigTable.fidoConcesso) {
          ris.cansend = false;
          ris.errormsg = i18n.__('CIRCUIT_AMOUNT_EXCEED_FIDO', usernameOrig);
          ris.errorcode = shared_consts.SENDRIS_CODES.EXCEED_FIDO;
        }

        if (accountdestTable.saldo + myqty > accountdestTable.qta_maxConcessa) {
          ris.cansend = false;
          ris.errormsg = i18n.__('CIRCUIT_AMOUNT_EXCEED_QTAMAX', extrarec.dest);
          ris.errorcode = shared_consts.SENDRIS_CODES.EXCEED_QTAMAX;
        }
      }

      if (!onlycheck) {
        // Add a Transaction !
        if (ris.cansend) {
          ris.rec = await Movement.addMov(
            idapp,
            accountorigTable,
            accountdestTable,
            myqty,
            extrarec.causal,
            extrarec.causalDest,
            extrarec.notifId,
            extrarec.idOrdersCart
          );
        }

        if (ris.cansend && ris.rec) {
          const circolanteAtt = this.getCircolanteSingolaTransaz(accountorigTable, accountdestTable);

          // Somma di tutte le transazioni
          circuittable.numTransazioni += 1;
          circuittable.totTransato += myqty;
          // circuittable.totCircolante = circuittable.totCircolante + (circolanteAtt - circolantePrec);
          circuittable.totCircolante = await Account.calcTotCircolante(idapp, circuittable._id);
          // await circuittable.save();
          paramstoupdate = {
            totTransato: circuittable.totTransato,
            totCircolante: circuittable.totCircolante,
            numTransazioni: circuittable.numTransazioni,
          };
          await Circuit.updateOne({ _id: circuittable }, { $set: paramstoupdate });

          extrarec.saldoOrig = tools.arrotondaA2Decimali(accountorigTable.saldo);
          extrarec.saldoDest = tools.arrotondaA2Decimali(accountdestTable.saldo);

          let orig = usernameOrig;
          if (extrarec.grouporig) {
            orig = extrarec.grouporig + ' (' + usernameOrig + ')';
          }
          if (extrarec.contoComOrig) {
            orig = extrarec.contoComOrig + ' (' + usernameOrig + ')';
          }
          let dest =
            (extrarec.dest ? extrarec.dest : '') +
            (extrarec.groupdest ? extrarec.groupdest : '') +
            (extrarec.contoComDest ? extrarec.contoComDest : '');

          ris.result = true;
          let causalDest = extrarec.causalDest ? 'Causale Destinatario: ' + extrarec.causalDest : '';
          let msg =
            '[<b>' +
            circuittable.name +
            '</b>]: Inviate Monete da ' +
            orig +
            ' a ' +
            dest +
            ' ' +
            myqty +
            ' ' +
            circuittable.symbol +
            ' [causale: ' +
            extrarec.causal +
            `]\n` +
            causalDest +
            `\nSaldi:\n${orig}: ` +
            extrarec.saldoOrig +
            ' ' +
            circuittable.symbol +
            '] ' +
            `\n${dest}: ` +
            extrarec.saldoDest +
            ' ' +
            circuittable.symbol +
            ']';
          console.log(msg);

          ris.useraccounts = await Account.getUserAccounts(idapp, usernameOrig);

          tools.writeTransactionLog(msg);

          tools.sendMsgTelegramToAdmin(idapp, msg);

          let mittente = orig;

          try {
            const paramsrec = {
              mittente,
              nomecircuito: circuittable.name,
              symbol: circuittable.symbol,
              qty: myqty,
              transactionDate: ris.rec.transactionDate,
              causale: extrarec.causal,
              causalDest: extrarec.causalDest,
            };
            if (extrarec.dest) {
              let myuserDest = await User.getUserByUsername(idapp, extrarec.dest);

              // Invia una email al destinatario !
              await sendemail.sendEmail_RisRicevuti(
                myuserDest.lang,
                myuserDest,
                myuserDest.email,
                idapp,
                paramsrec,
                extrarec
              );
            } else if (extrarec.groupdest || extrarec.contoComDest) {
              const groupDestoContoCom = extrarec.groupdest
                ? extrarec.groupdest
                : extrarec && extrarec.contoComDest
                ? extrarec.contoComDest
                : '';
              let arrusers = await MyGroup.getListAdminsByGroupName(idapp, groupDestoContoCom);
              if (arrusers.length <= 0) arrusers = await Circuit.getListAdminsByCircuitPath(idapp, groupDestoContoCom);

              paramsrec.groupDestoContoCom = groupDestoContoCom;

              for (let i = 0; i < arrusers.length; i++) {
                let myuserDest = await User.getUserByUsername(idapp, arrusers[i].username);

                // Invia una email al destinatario !
                await sendemail.sendEmail_RisRicevuti(myuserDest.lang, myuserDest, myuserDest.email, idapp, paramsrec);
              }
            }
          } catch (e) {
            console.error('Err Email sendCoins', e);
          }
        } else {
          // console.log('NON Inviate Monete da', usernameOrig, extrarec.grouporig, extrarec.dest, extrarec.groupdest, myqty, extrarec.causal);
        }
      }

      return ris;
    }
  } catch (e) {
    console.error('Err sendCoins', e);
    ris.result = false;
    return ris;
  }
};

// Rimuovo la Richiesta del Circuito
CircuitSchema.statics.removeReqCircuit = async function (idapp, username, name) {
  return await Circuit.updateOne({ idapp, name }, { $pull: { req_users: { username: { $in: [username] } } } });
};

// Rimuovo la Richiesta del Gruppo sul Circuito
CircuitSchema.statics.removeReqGroupCircuit = async function (idapp, groupname, name) {
  return await Circuit.updateOne({ idapp, name }, { $pull: { req_groups: { groupname: { $in: [groupname] } } } });
};

// Aggiungi agli utenti Rifiutati del Circuito

CircuitSchema.statics.refuseReqCircuit = async function (idapp, username, name) {
  return await Circuit.updateOne(
    { idapp, name },
    {
      $push: {
        refused_users: {
          username,
          date: new Date(),
        },
      },
    }
  );
};

CircuitSchema.statics.refuseReqGroupCircuit = async function (idapp, groupname, name) {
  return await Circuit.updateOne(
    { idapp, name },
    {
      $push: {
        refused_groups: {
          groupname,
          date: new Date(),
        },
      },
    }
  );
};

CircuitSchema.statics.updateData = async function (idapp, circuitname) {
  try {
    const { User } = require('./user');

    let aggr1 = [
      {
        $match: {
          idapp,
          'profile.mycircuits': {
            $elemMatch: { circuitname: { $eq: circuitname } },
          },
        },
      },
      { $group: { _id: null, count: { $sum: 1 } } },
    ];

    const ris = await User.aggregate(aggr1);

    let numMembers = 0;
    try {
      numMembers = ris && tools.isArray(ris) ? ris[0].count : 0;
    } catch (e) {}

    let paramstoupdate = {
      numMembers: numMembers,
    };
    const risult = await this.updateOne({ idapp, name: circuitname }, { $set: paramstoupdate });

    console.log('risult', risult);
  } catch (e) {
    console.error('Err', e);
  }
};

CircuitSchema.statics.setDeperimentoOff = async function () {
  return await Circuit.updateMany({}, { $set: { deperimento: false } }, { new: false });
};

CircuitSchema.statics.getNameByCircuitId = async function (circuitId) {
  let circuit = await Circuit.findOne({ _id: circuitId });
  if (circuit) return circuit.name;

  return '';
};
CircuitSchema.statics.getPathByCircuitName = async function (idapp, circuitName) {
  let circuit = await Circuit.findOne({ idapp, name: circuitName }).lean();
  if (circuit) return '/' + shared_consts.getDirectoryByTable('circuits') + '/' + circuit.path;

  return '';
};

CircuitSchema.statics.getCircuitByCircuitId = async function (circuitId) {
  return await Circuit.findOne({ _id: circuitId });
};

// getListAdminsByCircuitPath - ritorna oggetti interi + USER_ADMIN_CIRCUITS
// getListAdminsByCircuitPath - ritorna oggetti interi senza duplicati
CircuitSchema.statics.getListAdminsByCircuitPath = async function (idapp, circuitPath) {
  let circuit = await Circuit.findOne(
    {
      idapp,
      path: circuitPath,
      $or: [{ deleted: { $exists: false } }, { deleted: { $exists: true, $eq: false } }],
    },
    { admins: 1 }
  ).lean();

  let adminObjects = circuit && circuit.admins ? circuit.admins : [];

  // Aggiungi USER_ADMIN_CIRCUITS come oggetti
  let systemAdmins = shared_consts.USER_ADMIN_CIRCUITS.map((username) => ({
    username,
    date: null,
    _id: null,
  }));

  // Unisci e rimuovi duplicati per username
  let allAdmins = [...adminObjects, ...systemAdmins];
  let uniqueAdmins = allAdmins.filter(
    (admin, index, self) => index === self.findIndex((a) => a.username === admin.username)
  );

  return uniqueAdmins;
};

// Imposta a tutti i Conti Collettivi, i seguenti minimi e massimi
CircuitSchema.statics.setstrProvByIdCityCircuits = async function (idapp) {
  const { City } = require('../models/city');

  const arrcircuits = await Circuit.find({ idapp }).lean();
  try {
    for (const rec of arrcircuits) {
      let recstrProv = await City.findOne({ _id: rec.idCity[0] });
      if (recstrProv) {
        let objProv = {};
        objProv['strProv'] = recstrProv.prov;
        await Circuit.updateOne({ _id: rec._id }, { $set: objProv });
      }
    }
  } catch (e) {}
};

CircuitSchema.statics.AbilitaTuttiCircuiti = async function (idapp) {
  const ris = await Circuit.updateMany(
    { idapp },
    {
      $set: {
        transactionsEnabled: true,
      },
    }
  );

  return ris;
};

CircuitSchema.statics.AzzeraRegolamentiTuttiCircuiti = async function (idapp) {
  const ris = await Circuit.updateMany(
    { idapp },
    {
      $set: {
        regulation: '',
      },
    }
  );

  return ris;
};

// Imposta a tutti i Conti Personali, i seguenti minimi e massimi
CircuitSchema.statics.SetDefMinMaxPersonali = async function (idapp, valmin, valmax, circuitId) {
  if (circuitId) {
    const ris = await Circuit.updateOne(
      { _id: circuitId },
      {
        $set: {
          fido_scoperto_default: valmin,
          qta_max_default: valmax,
        },
      }
    );
  } else {
    const ris = await Circuit.updateMany(
      { idapp },
      {
        $set: {
          fido_scoperto_default: valmin,
          qta_max_default: valmax,
        },
      }
    );
  }
};

// Imposta a tutti i Conti Collettivi, i seguenti minimi e massimi
CircuitSchema.statics.getCircuitMyProvince = async function (idapp, username) {
  const { User } = require('../models/user');

  const myuser = await User.getUserByUsername(idapp, username);

  try {
    const circuit = await this.getCircuitByProvinceAndCard(
      idapp,
      myuser.profile.resid_province,
      myuser.profile.resid_card
    );

    if (circuit) {
      if (await User.ifAlreadyInCircuit(idapp, username, circuit.name)) {
        return circuit.name;
      }
    }

    return '[nessun Circuito]';
  } catch (e) {
    console.error('Error', e);
  }
};

// Imposta a tutti i Conti Collettivi, i seguenti minimi e massimi
CircuitSchema.statics.createCircuitIfNotExist = async function (req, idapp, province, card) {
  const { User } = require('../models/user');

  const admins = shared_consts.USER_ADMIN_CIRCUITS;
  const useradmin = shared_consts.USER_ADMIN_SINGOLO;

  let myrec = null;
  try {
    const circuit = await this.getCircuitByProvinceAndCard(idapp, province, card);

    const nomeprovincia = await Province.getStrProvinceByProv(province);

    if (!circuit && nomeprovincia) {
      const circ = new Circuit({
        idapp,
        name: 'Circuito RIS ' + nomeprovincia,
        path: 'ris' + tools.convertSpaces_ToUScore(nomeprovincia.toLowerCase()),
        strProv: province,
        card,
        photos: [],
        color: '#ff5500',
        deperimento: false,
        circuitiExtraProv: false,
        isCircItalia: false,
        enableOnlyIf1CircuitExist: false,
        transactionsEnabled: true, // Abilita cmq il circuito dall'inizio
        status: shared_consts.CIRCUIT_STATUS.FASE1_CREAZIONE_GRUPPO,
        symbol: 'RIS',
        fido_scoperto_default: 100,
        qta_max_default: 200,
        fido_scoperto_default_grp: shared_consts.CIRCUIT_PARAMS.SCOPERTO_MIN_GRP,
        qta_max_default_grp: shared_consts.CIRCUIT_PARAMS.SCOPERTO_MAX_GRP,
        valuta_per_euro: 1,
        totTransato: 0,
        numTransazioni: 0,
        totCircolante: 0,
        date_created: new Date(),
        admins: admins.map((username) => ({ username })),
        askManagerToEnter: false,
        sendEmailAfterAskingToEnter: true,
        circuitoIndipendente: false,
      });

      myrec = await circ.save();

      if (myrec) {
        // nuovo Circuito:
        await User.setCircuitCmd(
          idapp,
          useradmin,
          myrec.name,
          shared_consts.CIRCUITCMD.CREATE,
          true,
          useradmin,
          myrec
        ).then((ris) => {});

        // aggiungi il creatore al Circuito stesso
        await User.setCircuitCmd(
          idapp,
          useradmin,
          myrec.name,
          shared_consts.CIRCUITCMD.SET,
          true,
          useradmin,
          myrec
        ).then((ris) => {});
      }

      msg = 'Nuovo Circuito Creato in Automatico: ' + myrec.name + ' (da ' + req.user.username + ')';
      tools.sendMsgTelegramToAdmin(idapp, msg);
    }
  } catch (e) {
    console.error('Error', e);
  }

  return myrec;
};

CircuitSchema.statics.getListAdmins = async function (idapp, circuitname) {
  let arr = await Circuit.findOne(
    {
      idapp,
      name: circuitname,
      $or: [{ deleted: { $exists: false } }, { deleted: { $exists: true, $eq: false } }],
    },
    { admins: 1 }
  ).lean();

  let mystr = '';

  if (arr) {
    for (const admin of arr.admins) {
      mystr += (await tools.getAhref(admin.username, await tools.getLinkUserTelegram(idapp, admin.username))) + ', ';
    }
  }

  return { str: mystr, num: arr ? arr.admins.length : 0 };
};

CircuitSchema.statics.isAdminCircuit = async function (idapp, circuitname, username) {
  let arr = await Circuit.findOne(
    {
      idapp,
      name: circuitname,
      $or: [{ deleted: { $exists: false } }, { deleted: { $exists: true, $eq: false } }],
    },
    { admins: 1 }
  ).lean();

  if (arr) {
    for (const admin of arr.admins) {
      if (shared_consts.USER_ADMIN_CIRCUITS.includes(username) || admin.username === username) return true;
    }
  }

  return false;
};

CircuitSchema.statics.getListCircuitsByUsername = async function (idapp, username, groupname) {
  let mystr = '';
  const { User } = require('../models/user');
  const myuser = await User.getUserByUsername(idapp, username);

  const useraccounts = await Account.getUserAccounts(idapp, username);
  const groupsaccounts = await Account.getGroupAccounts(idapp, groupname);

  for (let account of useraccounts) {
    if (myuser.profile.mycircuits.find((rec) => rec.circuitname === account.circuit.name)) {
      if (account.groupname === '') {
        mystr += '\n👉🏻 ' + account.circuit.name + '\n';
        mystr += '   [Saldo: ' + account.saldo + ' RIS, ';
        mystr += ' Fiducia: ' + account.fidoConcesso + ' RIS, ';
        mystr += ' Transato: ' + account.totTransato + ' RIS]';
      }
    }
  }

  for (let account of groupsaccounts) {
    if (myuser.profile.mycircuits.find((rec) => rec.circuitname === account.circuit.name)) {
      mystr += '\n GRUPPO: 👉🏻 <b>' + account.groupname + '</b> in ' + account.circuit.name + '\n';
      mystr += '   [Saldo: ' + account.saldo + ' RIS, ';
      mystr += ' Fiducia: ' + account.fidoConcesso + ' RIS, ';
      mystr += ' Transato: ' + account.totTransato + ' RIS]';
    }
  }

  if (!mystr) {
    mystr = '[Nessun Circuito]';
  }

  return mystr;
};

CircuitSchema.statics.SetDefMinMaxCollettivi = async function (idapp, valmin, valmax, circuitId) {
  if (circuitId) {
    const ris = await Circuit.updateOne(
      { _id: circuitId },
      {
        $set: {
          fido_scoperto_default_grp: valmin,
          qta_max_default_grp: valmax,
        },
      }
    );
  } else {
    const ris = await Circuit.updateMany(
      { idapp },
      {
        $set: {
          fido_scoperto_default_grp: valmin,
          qta_max_default_grp: valmax,
        },
      }
    );
  }
};

CircuitSchema.statics.setFido = async function (idapp, username, circuitName, groupname, username_action) {
  try {
    mycircuit = await Circuit.findOne({ idapp, name: circuitName }).lean();
    if (mycircuit) {
      const circuitId = mycircuit._id;
      let account = null;
      let fido = 0;
      let qtamax = 0;
      let variato = false;
      let variato2 = false;

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

        const myuser = await User.getUserByUsername(idapp, username);

        // Se è il circuito Nazionale, allora prende i valori dal proprio Circuito Locale:
        const accountsuser = await Account.getUserAccounts(idapp, username);
        if (accountsuser) {
          // Se lo trovo della mia provincia, prendo quello
          account = accountsuser.find(
            (account) =>
              account.circuit.strProv === myuser.profile.resid_province &&
              (account.circuit.card === myuser.profile.resid_card || !myuser.profile.resid_card)
          );
          if (!account && accountsuser.length > 0) {
            // Se non lo trovo, prendo il primo in cui sono entrato !
            account = accountsuser[0];
          }
          if (account && account.circuit) {
            if (groupname) {
              qtamax = account.circuit.qta_max_default_grp * shared_consts.CIRCUIT_CFG.MULT_FIDO_GROUP;
              fido = account.circuit.fido_scoperto_default_grp * shared_consts.CIRCUIT_CFG.MULT_FIDO_GROUP;
            } else {
              qtamax = account.circuit.qta_max_default * shared_consts.CIRCUIT_CFG.MULT_FIDO_USER;
              fido = account.circuit.fido_scoperto_default * shared_consts.CIRCUIT_CFG.MULT_FIDO_USER;
            }
          }
        } else {
          // Se non ho Circuiti locali, non applico il Fido !
          return null;
        }
      } else {
        account = await Account.getAccountByUsernameAndCircuitId(idapp, username, circuitId, true, true, groupname, '');
        if (groupname) fido = mycircuit.fido_scoperto_default_grp;
        else fido = mycircuit.fido_scoperto_default;
      }

      if (account) {
        if (qtamax > 0) {
          variato = await Account.updateQtaMax(idapp, username, groupname, circuitId, qtamax);
        }

        const ris = await Account.updateFido(idapp, username, groupname, circuitId, fido, username_action);
        if (ris) {
          return {
            qta_maxConcessa: qtamax,
            fidoConcesso: fido,
            username_admin_abilitante: username_action,
            changed: variato || (ris && ris.modifiedCount > 0),
          };
        }
      }
    }
  } catch (e) {
    console.error('Err:', e);
  }
  return null;
};
CircuitSchema.statics.getFido = async function (idapp, username, circuitName, groupname) {
  try {
    mycircuit = await Circuit.findOne({ idapp, name: circuitName }).lean();
    if (mycircuit) {
      const circuitId = mycircuit._id;

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

        const myuser = await User.getUserByUsername(idapp, username);

        // Se è il circuito Nazionale, allora prende i valori dal proprio Circuito Locale:
        const accountsuser = await Account.getUserAccounts(idapp, username);
        if (accountsuser) {
          // Se lo trovo della mia provincia, prendo quello
          account = accountsuser.find(
            (account) =>
              account.circuit.strProv === myuser.profile.resid_province &&
              (account.circuit.card === myuser.profile.resid_card || !myuser.profile.resid_card)
          );
          if (!account && accountsuser.length > 0) {
            // Se non lo trovo, prendo il primo in cui sono entrato !
            account = accountsuser[0];
          }
        } else {
          // Se non ho Circuiti locali, non applico il Fido !
          return 0;
        }
      } else {
        account = await Account.getAccountByUsernameAndCircuitId(idapp, username, circuitId, true, true, groupname, '');
      }

      if (account) {
        return account.fidoConcesso;
      }

      return 0;
    }
  } catch (e) {
    console.error('Err:', e);
  }
  return null;
};

CircuitSchema.statics.CheckTransazioniCircuiti = async function (correggi, options) {
  const { User } = require('../models/user');
  const { MyGroup } = require('../models/mygroup');
  const { SendNotif } = require('../models/sendnotif');

  const idapp = tools.RISO;

  try {
    console.log('---------  INIZIO CONTROLLO CheckTransazioniCircuiti -----------');

    if (correggi) console.log('CORREZIONE !');
    else console.log('SOLO VERIFICA');

    if (correggi) {
      // Trova tutti i documenti che contengono circuitname a null nell'array mycircuits
      const usersWithNullCircuit = await User.find({ idapp, 'profile.mycircuits.circuitname': null });

      // Itera su ciascun documento
      for (const user of usersWithNullCircuit) {
        // Rimuove i campi null dall'array mycircuits
        user.profile.mycircuits = user.profile.mycircuits.filter((circuit) => circuit.circuitname !== null);

        // Salva le modifiche al documento
        await User.findOneAndUpdate({ _id: user._id }, { $set: { 'profile.mycircuits': user.profile.mycircuits } });
      }
    }

    let usersWithDuplicateCircuits = await User.aggregate([
      {
        $unwind: '$profile.mycircuits',
      },
      {
        $group: {
          _id: {
            userId: '$_id',
            username: '$username',
            circuitname: '$profile.mycircuits.circuitname',
          },
          count: { $sum: 1 },
        },
      },
      {
        $match: {
          count: { $gt: 1 },
        },
      },
      {
        $group: {
          _id: '$_id.userId',
          username: { $first: '$_id.username' },
          duplicatedCircuits: {
            $push: '$_id.circuitname',
          },
        },
      },
    ]);

    if (usersWithDuplicateCircuits.length > 0) {
      console.log('Utenti con circuitname duplicati:');
      usersWithDuplicateCircuits.forEach((user) => {
        console.log('Username:', user.username);
        console.log('Circuiti duplicati:', user.duplicatedCircuits);
      });

      if (correggi) {
        // CORREGGI DUPLICATI NEI CIRCUITI
        for (const user of usersWithDuplicateCircuits) {
          // Troviamo l'utente dal suo _id e aggiorniamo il suo documento
          const arraycirc = await User.findOne({ _id: user._id }).lean();

          let risdel = await User.updateOne(
            { _id: user._id },
            { $pull: { 'profile.mycircuits': { circuitname: { $in: user.duplicatedCircuits } } } }
          );

          let risadd = await User.updateOne(
            { _id: user._id },
            {
              $push: {
                'profile.mycircuits': {
                  $each: user.duplicatedCircuits.map((circuitname) => ({
                    circuitname,
                    date: arraycirc.profile.mycircuits.find((rec) => rec.circuitname === circuitname).date,
                  })),
                },
              },
            }
          );
          console.log('DEL', risdel, 'risadd', risadd);
        }
      }

      console.log('*** FINE DUPLICATI *** ');
    } else {
      console.log('Nessun utente ha circuitname duplicati.');
    }

    let numtransazionitot = 0;

    const arrcircuits = await Circuit.find({ idapp });
    for (const circuit of arrcircuits) {
      let strusersnotinaCircuit = '';
      let strusersnotExist = '';
      numtransazionitot = 0;

      let qta = 0;

      let mystr = '';

      // 1. Calcola la somma di tutti i Saldi

      // prendo la lista di tutti gli account del circuito

      let circuitId = circuit._id;

      const accounts = await Account.find({ idapp, circuitId }).lean();

      // CONTROLLA DUPLICATI !

      const usernameCounts = accounts.reduce((acc, curr) => {
        if (curr.username !== '') {
          acc[curr.username] = (acc[curr.username] || 0) + 1;
        }
        return acc;
      }, {});

      const duplicatedUsernames = Object.keys(usernameCounts).filter((username) => usernameCounts[username] > 1);

      if (duplicatedUsernames.length > 0) {
        mystr += ' Esistono username duplicati (escludendo quelli vuoti):' + duplicatedUsernames;
      }

      let saldotot = 0;

      let ris = await User.find(
        {
          'profile.mycircuits': { $elemMatch: { circuitname: circuit.name } },
        },
        'username'
      ).lean();

      let arrusers_byprofile = ris ? ris.map((user) => user.username) : [];

      let risgroups = await MyGroup.find(
        {
          mycircuits: { $elemMatch: { circuitname: circuit.name } },
        },
        'groupname'
      ).lean();

      let arrgroups_byprofile = risgroups ? risgroups.map((group) => group.groupname) : [];

      let arrusers_byaccounts = [];
      let ind = 0;
      let stracc = '';

      for (const account of accounts) {
        let aggiorna = false;

        if (account.username && !arrusers_byaccounts.includes(account.username)) {
          arrusers_byaccounts.push(account.username);
        } else if (account.groupname && !arrusers_byaccounts.includes(account.groupname)) {
          arrusers_byaccounts.push(account.groupname);
        } else if (account.contocom && !arrusers_byaccounts.includes(account.contocom)) {
          arrusers_byaccounts.push(account.contocom);
        }

        // per ogni Account ricalcolo il numero di transazioni avvenute in Entrata/uscita
        let result = await Movement.aggregate([
          {
            $match: {
              $or: [{ accountFromId: account._id }, { accountToId: account._id }],
            },
          },
          {
            $group: {
              _id: null,
              numtransactions: { $sum: 1 },
              totTransato: { $sum: { $abs: '$amount' } },
              sentCount: {
                $sum: {
                  $cond: [{ $eq: ['$accountFromId', account._id] }, 1, 0],
                },
              },
              receivedCount: {
                $sum: {
                  $cond: [{ $eq: ['$accountToId', account._id] }, 1, 0],
                },
              },
              saldo: {
                $sum: {
                  $cond: [
                    { $eq: ['$accountToId', account._id] },
                    '$amount',
                    {
                      $cond: [{ $eq: ['$accountFromId', account._id] }, { $multiply: ['$amount', -1] }, 0],
                    },
                  ],
                },
              },
            },
          },
        ]);

        let numtransactions = result && result.length > 0 ? result[0].numtransactions : 0;
        let sentCount = result && result.length > 0 ? result[0].sentCount : 0;
        let receivedCount = result && result.length > 0 ? result[0].receivedCount : 0;
        let totTransato = result && result.length > 0 ? result[0].totTransato : 0;
        let saldo = result && result.length > 0 ? result[0].saldo : 0;

        // TRANSAZIONI PENDENTI:
        let saldo_pend = 0;
        let pendingtransactionsMittente = await SendNotif.getSumPendingTransactionsMittente(
          account.idapp,
          account.username,
          circuit.name,
          account.groupname
        );
        if (pendingtransactionsMittente.length > 0) {
          let saldopendingMitt = pendingtransactionsMittente.reduce((sum, rec) => sum + rec.extrarec.qty, 0);
          // transatopending = pendingtransactionsMittente.reduce((sum, rec) => sum + Math.abs(rec.extrarec.qty), 0);

          saldo_pend = saldo - saldopendingMitt;
        } else {
          saldo_pend = saldo;
        }

        let strtemp = '';

        if (numtransactions > 0) {
          if (correggi) await Account.findOneAndUpdate({ _id: account._id }, { $set: { numtransactions } });
        }
        if (saldo !== account.saldo) {
          aggiorna = true;
          strtemp += ' SALDO DIFFERENTE ! => ' + '\nPRIMA: ' + account.saldo + '\nDOPO: ' + saldo;
          if (correggi) await Account.findOneAndUpdate({ _id: account._id }, { $set: { saldo } });
        }
        if (account.saldo_pend === undefined) {
          await Account.findOneAndUpdate({ _id: account._id }, { $set: { saldo_pend: 0 } });
        }
        if (saldo_pend !== account.saldo_pend) {
          aggiorna = true;
          strtemp += ' SALDO_PENDENTE DIFF. ! => ' + '\nPRIMA: ' + account.saldo_pend + '\nDOPO: ' + saldo_pend;
          if (correggi) await Account.findOneAndUpdate({ _id: account._id }, { $set: { saldo_pend } });
        }
        if (!account.totTransato || totTransato !== account.totTransato) {
          if (totTransato > account.totTransato || account.totTransato === undefined)
            if (correggi) await Account.findOneAndUpdate({ _id: account._id }, { $set: { totTransato } });
        }

        await Account.findOneAndUpdate({ _id: account._id }, { $set: { sent: sentCount, received: receivedCount } });

        saldotot += account.saldo;

        // if (account.totTransato === NaN || account.totTransato === undefined)
        //   stracc += ' TOTTRANSATO => ' + account.totTransato;

        if (account.totTransato) qta += account.totTransato;
        if (account.numtransactions) numtransazionitot += account.numtransactions;

        if (aggiorna && strtemp) {
          stracc += '\n   ** Account ' + account.username + '\n' + strtemp;
        }

        // await account.calcPending();
        ind++;
      } // FINE ACCOUNT

      if (options?.setnumtransaction) {
        circuit.numTransazioni = numtransazionitot;
        await circuit.save(); // salva su db
      }

      let numaccounts = accounts.length;
      let esistecontocom = accounts.find((rec) => rec.hasOwnProperty('contocom') && rec.contocom !== '');

      let numacc_profile = arrusers_byprofile.length + arrgroups_byprofile.length;
      if (esistecontocom && esistecontocom.contocom === circuit.path) {
        numacc_profile++;
      }

      if (numacc_profile !== numaccounts) {
        mystr += ' IL NUMERO DI UTENTI NON COINCIDONO ! \n';
        mystr += 'Utenti Profilo = ' + numacc_profile + '\n';
        mystr += 'Utenti Accounts = ' + arrusers_byaccounts.length + '\n';
      }

      saldotot = saldotot.toFixed(2);

      // mystr += ' numaccounts=' + numaccounts;
      if (strusersnotinaCircuit) mystr += ' Utenti non presenti nel Circuito ! => ' + strusersnotinaCircuit;
      if (strusersnotExist) mystr += ' Utenti non più esistenti ! => ' + strusersnotExist;

      // Verifica se saldotot è uguale a ZERO
      if (saldotot != 0) {
        mystr += '*** ATTENZIONE! ' + circuit.name + ' ha come somma un saldo di ' + saldotot + ' invece che ZERO';
      } else {
        if (numtransazionitot) mystr += ' qta=' + qta + ' numtransazionitot ' + numtransazionitot;
      }

      if (mystr || stracc) {
        console.log('*************************  ' + circuit.name + ':');
        console.log(mystr);
        if (stracc) console.log(stracc);
      }
    }

    console.log('---------  FINE CONTROLLO CheckTransazioniCircuiti -----------', 'Transazioni = ', numtransazionitot);
  } catch (e) {
    console.error('Err', e);
  }
};

CircuitSchema.statics.replaceAllCircuitNames = async function (idapp) {
  const Circuit = this;

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

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

  const myfind = { idapp };

  let circuits = [];
  try {
    circuits = await Circuit.find(myfind);

    let quanti = 0;

    for (const circuit of circuits) {
      if (!circuit || !circuit._id) {
        console.error('Error: circuit is null or has no _id property');
        continue;
      }
      const circuitId = circuit._id;

      let provincia = '';
      if (circuit.idCity && circuit.idCity.length > 0) {
        provincia = await City.getProvinceByIdCity(circuit.idCity[0]);
      }
      if (!provincia) provincia = circuit.strProv;
      if (provincia) {
        provincia = await Province.getStrProvinceByProv(provincia);
      }

      if (!provincia) {
        console.log('PROVINCIA NON ESISTENTE !', circuit.name);
      }

      let path = '';

      if (!circuit.circuitiExtraProv) {
        let newname = 'Circuito RIS ' + provincia;

        // Se newname contiene 'ROMA', allora non aggiorna

        if (circuit.name == 'RIS Roma Sud Est ' || circuit.name === 'Circuito RIS Roma Sud Est') {
          newname = 'Circuito RIS Roma Sud Est';
        } else if (circuit.name == 'Circuito RIS Roma Sud e Litora') {
          newname = 'Circuito RIS Roma Sud e Litora';
        } else if (circuit.name.trim() === 'RISO Roma Nord' || circuit.name.trim() === 'Circuito RISO Roma Nord') {
          newname = 'Circuito RIS Roma Nord';
        } else if (circuit.name == 'Circuito RIS Benevento' || circuit.name == 'Circuito RIS Campania') {
          newname = 'Circuito RIS Campania';
          path = 'riscampania';
        } else if (circuit.name == 'Circuito RIS Milano Est') {
          newname = 'Circuito RIS Milano Est';
        } else if (circuit.name == 'Circuito RIS Repubblica di San Marino') {
          newname = 'Circuito RIS Repubblica di San Marino';
        }

        if ((newname !== circuit.name && newname.indexOf('ROMA') === -1) || path) {
          console.log(`Sostituisci ${circuit.name} con ${newname}`);

          quanti++;

          if (path) {
            // Update path
            await Circuit.findOneAndUpdate({ _id: circuitId }, { $set: { path } }).catch((e) =>
              console.error('Err ', e)
            );
          }

          await Circuit.findOneAndUpdate({ _id: circuitId }, { $set: { name: newname } }).catch((e) =>
            console.error('Err ', e)
          );

          // Rename profile.mycircuits.circuitname in User
          await User.renameCircuitName(idapp, circuit.name, newname).catch((e) => console.error('Err ', e));

          await MyGroup.renameCircuitName(idapp, circuit.name, newname).catch((e) => console.error('Err ', e));
        }
      }
    }
    console.log('Circuiti aggiornati: ' + quanti);
  } catch (e) {
    console.error('Err ', e);
    return;
  }
};

CircuitSchema.statics.getnumCircuits = async function (idapp) {
  const Circuit = this;

  const numcirc = await Circuit.countDocuments({
    idapp,
    transactionsEnabled: true,
  });

  return numcirc;
};

CircuitSchema.statics.getnumActiveCircuits = async function (idapp) {
  const Circuit = this;

  const numcirc = await Circuit.countDocuments({
    idapp,
    transactionsEnabled: true,
    totTransato: { $gt: 1 },
  });

  return numcirc;
};

CircuitSchema.statics.addMovementByOrdersCart = async function (ordersCart, usernameDest, groupDest) {
  const { User } = require('../models/user');

  const idapp = ordersCart.idapp;

  let extrarec = {
    causal: 'Pagato Ordine n.' + ordersCart.numorder,
    circuitname: 'Euro',
    idOrdersCart: ordersCart._id,
    qty: ordersCart.totalPrice,
    dest: usernameDest,
    groupdest: groupDest,
    contoComDest: '',
    causalDest: '',
  };

  const usernameOrig = await User.getUsernameById(idapp, ordersCart.userId);

  return this.sendCoins(false, idapp, usernameOrig, extrarec);
};

CircuitSchema.statics.getCircuitiExtraProvinciali = async function (idapp) {
  const Circuit = this;

  const circuits = await Circuit.find({ idapp, circuitiExtraProv: true });

  return circuits;
};

CircuitSchema.statics.ricalcolaNumTransazioni = async function (circuitId) {
  const Circuit = this;

  // +TODO: Ricalcola il numero delle transazioni avvenute
};
CircuitSchema.statics.getCircuitoItalia = async function (idapp) {
  const Circuit = this;

  const circuit = await Circuit.findOne({ idapp, isCircItalia: true });

  return circuit;
};

CircuitSchema.statics.getSymbolByCircuitId = async function (circuitId) {
  const Circuit = this;

  const circuit = await Circuit.findOne({ _id: circuitId }, { symbol: 1});

  return circuit?.symbol || '';
};
CircuitSchema.statics.isEnableToReceiveEmailByExtraRec = async function (idapp, recnotif) {
  let ricevo = true;
  if (recnotif.tag === 'setfido') {
    // Controllo se l'utente ha scelto di ricevere l'email
  }

  return ricevo;
};

const Circuit = mongoose.model('Circuit', CircuitSchema);

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

module.exports = { Circuit };
