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 { Account } = require('../models/account');

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

const MovementSchema = new Schema({
  _id: {
    type: String,
    default: function () {
      return new ObjectID().toString();
    },
  },
  idapp: {
    type: String,
  },
  notifId: {
    type: String,
  },
  transactionDate: {
    type: Date,
  },
  accountFromId: {
    type: String,
  },
  accountToId: {
    type: String,
  },
  idOrdersCart: { type: Schema.Types.ObjectId, ref: 'OrdersCart' },
  causal_table: {
    type: String,
  },
  causal_IdRec: {
    type: String,
  },
  amount: {
    type: Number,
  },
  causal: {
    type: String,
    default: '',
  },
  residual: {
    type: Number,
    default: 0,
  },
  expiringDate: {
    type: Date,
  },
  confirmed: {
    type: Boolean,
    default: false,
  },
});

MovementSchema.statics.findAllIdApp = async function (idapp) {
  const MyMovement = this;

  const myfind = { idapp };

  return await MyMovement.find(myfind, (err, arrrec) => {
    return arrrec;
  });
};

MovementSchema.pre('save', async function (next) {
  if (this.isNew) {

    this.transactionDate = new Date();
  }

  next();
});

MovementSchema.statics.getFieldsForSearch = function () {
  return [
    { field: 'causal', type: tools.FieldType.string },
    { field: 'amount', type: tools.FieldType.number },
  ];

};

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

MovementSchema.statics.addMov = async function (idapp, accountFromIdTable, accountToIdTable, amount, causal, notifId, idOrdersCart) {

  try {
    // Only positive values
    amount = Math.abs(amount);

    let mymov = await Movement.create(
      {
        idapp,
        transactionDate: new Date(),
        accountFromId: accountFromIdTable._id,
        accountToId: accountToIdTable._id,
        idOrdersCart,
        amount,
        causal,
        residual: 0,
        notifId,
        // expiringDate:
      },
    );

    if (mymov) {
      // Update saldo dell'Account
      await Account.addtoSaldo(accountToIdTable, amount, true);

      await Account.addtoSaldo(accountFromIdTable, -amount, false);

      return mymov;
    }
  } catch (e) {
    console.error('Error in addMov', e.message);
  }
};

MovementSchema.statics.getQueryMovsByCircuitId = async function (idapp, username, groupname, contocom, circuitId) {

  try {
    if (!circuitId) {
      return [];
    }
    const myaccount = await Account.getAccountByUsernameAndCircuitId(idapp, username, circuitId, false, true, groupname, contocom);



    if (myaccount) {

      let aggr1 = [
        {
          $match: {
            idapp,
            $or: [
              { accountFromId: myaccount._id },
              { accountToId: myaccount._id }],
          },
        },
        {
          $lookup: {
            from: 'accounts',
            localField: 'accountFromId',
            foreignField: '_id',
            as: 'accfrom',
          },
        },
        { $unwind: '$accfrom' },
        {
          $lookup: {
            from: 'users',
            let: { username: '$accfrom.username', idapp: '$accfrom.idapp' },
            pipeline: [
              {
                $match:
                {
                  $expr:
                  {
                    $and:
                      [
                        { $eq: ['$$username', '$username'] },
                        { $eq: ['$$idapp', '$idapp'] },
                      ],
                  },
                },
              },
            ],
            as: 'userfrom',
          },
        },
        {
          $unwind: {
            path: '$userfrom',
            preserveNullAndEmptyArrays: true,
          },
        },
        {
          $lookup: {
            from: 'mygroups',
            let: { groupname: '$accfrom.groupname', idapp: '$accfrom.idapp' },
            pipeline: [
              {
                $match:
                {
                  $expr:
                  {
                    $and:
                      [
                        { $eq: ['$$groupname', '$groupname'] },
                        { $eq: ['$$idapp', '$idapp'] },
                      ],
                  },
                },
              },
            ],
            as: 'groupfrom',
          },
        },
        {
          $unwind: {
            path: '$groupfrom',
            preserveNullAndEmptyArrays: true,
          },
        },

        {
          $lookup: {
            from: 'circuits',
            let: { contocom: '$accfrom.contocom', idapp: '$accfrom.idapp' },
            pipeline: [
              {
                $match:
                {
                  $expr:
                  {
                    $and:
                      [
                        { $eq: ['$$contocom', '$path'] },
                        { $eq: ['$$idapp', '$idapp'] },
                      ],
                  },
                },
              },
            ],
            as: 'contocomfrom',
          },
        },
        {
          $unwind: {
            path: '$contocomfrom',
            preserveNullAndEmptyArrays: true,
          },
        },
        {
          $lookup: {
            from: 'accounts',
            localField: 'accountToId',
            foreignField: '_id',
            as: 'accto',
          },
        },
        { $unwind: '$accto' },
        {
          $lookup: {
            from: 'circuits',
            localField: 'accfrom.circuitId',
            foreignField: '_id',
            as: 'circuitfrom',
          },
        },
        {
          $unwind: '$circuitfrom',
        },
        {
          $lookup: {
            from: 'circuits',
            localField: 'accto.circuitId',
            foreignField: '_id',
            as: 'circuitto',
          },
        },
        {
          $unwind: '$circuitto',
        },
        {
          $lookup: {
            from: 'users',
            let: { username: '$accto.username', idapp: '$accto.idapp' },
            pipeline: [
              {
                $match:
                {
                  $expr:
                  {
                    $and:
                      [
                        { $eq: ['$$username', '$username'] },
                        { $eq: ['$$idapp', '$idapp'] },
                      ],
                  },
                },
              },
            ],
            as: 'userto',
          },
        },
        {
          $unwind: {
            path: '$userto',
            preserveNullAndEmptyArrays: true,
          },
        },
        {
          $lookup: {
            from: 'mygroups',
            let: { groupname: '$accto.groupname', idapp: '$accto.idapp' },
            pipeline: [
              {
                $match:
                {
                  $expr:
                  {
                    $and:
                      [
                        { $eq: ['$$groupname', '$groupname'] },
                        { $eq: ['$$idapp', '$idapp'] },
                      ],
                  },
                },
              },
            ],
            as: 'groupto',
          },
        },
        {
          $unwind: {
            path: '$groupto',
            preserveNullAndEmptyArrays: true,
          },
        },
        {
          $lookup: {
            from: 'circuits',
            let: { contocom: '$accto.contocom', idapp: '$accto.idapp' },
            pipeline: [
              {
                $match:
                {
                  $expr:
                  {
                    $and:
                      [
                        { $eq: ['$$contocom', '$path'] },
                        { $eq: ['$$idapp', '$idapp'] },
                      ],
                  },
                },
              },
            ],
            as: 'contocomto',
          },
        },
        {
          $unwind: {
            path: '$contocomto',
            preserveNullAndEmptyArrays: true,
          },
        },
        {
          $project:
          {
            transactionDate: 1,
            amount: 1,
            causal: 1,
            notifId: 1,
            'circuitfrom.symbol': 1,
            'circuitto.symbol': 1,
            'userfrom.verified_by_aportador': 1,
            'userfrom.username': 1,
            'userfrom.profile.img': 1,
            'userto.username': 1,
            'userto.profile.img': 1,
            'userto.verified_by_aportador': 1,
            'groupfrom.groupname': 1,
            'groupfrom.verified_by_aportador': 1,
            'groupfrom.title': 1,
            'groupfrom.photos': 1,
            'groupto.groupname': 1,
            'groupto.title': 1,
            'groupto.photos': 1,
            'groupto.verified_by_aportador': 1,
            'contocomfrom.path': 1,
            'contocomfrom.name': 1,
            'contocomto.path': 1,
            'contocomto.name': 1,
          },
        },

      ];

      return aggr1;
    }

  } catch (e) {
    return [];
  }

  return [];
};


MovementSchema.statics.getQueryAllUsersMovsByCircuitId = async function (idapp, circuitId) {

  try {
    if (!circuitId) {
      return [];
    }
    let aggr1 = [
      {
        $match: {
          idapp,
        },
      },
      {
        $lookup: {
          from: 'accounts',
          localField: 'accountFromId',
          foreignField: '_id',
          as: 'accfrom',
        },
      },
      { $unwind: '$accfrom' },
      {
        $lookup: {
          from: 'users',
          let: { username: '$accfrom.username', idapp: '$accfrom.idapp' },
          pipeline: [
            {
              $match:
              {
                $expr:
                {
                  $and:
                    [
                      { $eq: ['$$username', '$username'] },
                      { $eq: ['$$idapp', '$idapp'] },
                    ],
                },
              },
            },
          ],
          as: 'userfrom',
        },
      },
      {
        $unwind: {
          path: '$userfrom',
          preserveNullAndEmptyArrays: true,
        },
      },
      {
        $lookup: {
          from: 'mygroups',
          let: { groupname: '$accfrom.groupname', idapp: '$accfrom.idapp' },
          pipeline: [
            {
              $match:
              {
                $expr:
                {
                  $and:
                    [
                      { $eq: ['$$groupname', '$groupname'] },
                      { $eq: ['$$idapp', '$idapp'] },
                    ],
                },
              },
            },
          ],
          as: 'groupfrom',
        },
      },
      {
        $unwind: {
          path: '$groupfrom',
          preserveNullAndEmptyArrays: true,
        },
      },
      {
        $lookup: {
          from: 'circuits',
          let: { contocom: '$accfrom.contocom', idapp: '$accfrom.idapp' },
          pipeline: [
            {
              $match:
              {
                $expr:
                {
                  $and:
                    [
                      { $eq: ['$$contocom', '$path'] },
                      { $eq: ['$$idapp', '$idapp'] },
                    ],
                },
              },
            },
          ],
          as: 'contocomfrom',
        },
      },
      {
        $unwind: {
          path: '$contocomfrom',
          preserveNullAndEmptyArrays: true,
        },
      },
      {
        $lookup: {
          from: 'accounts',
          localField: 'accountToId',
          foreignField: '_id',
          as: 'accto',
        },
      },
      {
        $unwind: {
          path: '$accto',
          preserveNullAndEmptyArrays: true,
        },
      },
      {
        $match: { 'accto.circuitId': circuitId },
      },
      {
        '$lookup': {
          'from': 'circuits',
          'localField': 'accfrom.circuitId',
          'foreignField': '_id',
          'as': 'circuitfrom',
        },
      },
      {
        $unwind: {
          path: '$circuitfrom',
          preserveNullAndEmptyArrays: true,
        },
      },
      {
        '$lookup': {
          'from': 'circuits',
          'localField': 'accto.circuitId',
          'foreignField': '_id',
          'as': 'circuitto',
        },
      },
      {
        $unwind: {
          path: '$circuitto',
          preserveNullAndEmptyArrays: true,
        },
      },
      {
        $lookup: {
          from: 'users',
          let: { username: '$accto.username', idapp: '$accto.idapp' },
          pipeline: [
            {
              $match:
              {
                $expr:
                {
                  $and:
                    [
                      { $eq: ['$$username', '$username'] },
                      { $eq: ['$$idapp', '$idapp'] },
                    ],
                },
              },
            },
          ],
          as: 'userto',
        },
      },
      {
        $unwind: {
          path: '$userto',
          preserveNullAndEmptyArrays: true,
        },
      },
      {
        $lookup: {
          from: 'mygroups',
          let: { groupname: '$accto.groupname', idapp: '$accto.idapp' },
          pipeline: [
            {
              $match:
              {
                $expr:
                {
                  $and:
                    [
                      { $eq: ['$$groupname', '$groupname'] },
                      { $eq: ['$$idapp', '$idapp'] },
                    ],
                },
              },
            },
          ],
          as: 'groupto',
        },
      },
      {
        $unwind: {
          path: '$groupto',
          preserveNullAndEmptyArrays: true,
        },
      },
      {
        $lookup: {
          from: 'circuits',
          let: { contocom: '$accto.contocom', idapp: '$accto.idapp' },
          pipeline: [
            {
              $match:
              {
                $expr:
                {
                  $and:
                    [
                      { $eq: ['$$contocom', '$path'] },
                      { $eq: ['$$idapp', '$idapp'] },
                    ],
                },
              },
            },
          ],
          as: 'contocomto',
        },
      },
      {
        $unwind: {
          path: '$contocomto',
          preserveNullAndEmptyArrays: true,
        },
      },
      {
        $project:
        {
          transactionDate: 1,
          amount: 1,
          causal: 1,
          notifId: 1,
          'circuitfrom.symbol': 1,
          'circuitto.symbol': 1,
          'userfrom.username': 1,
          'userfrom.profile.img': 1,
          'userto.username': 1,
          'userto.profile.img': 1,
          'groupfrom.groupname': 1,
          'groupfrom.title': 1,
          'groupto.groupname': 1,
          'groupto.title': 1,
          'contocomfrom.path': 1,
          'contocomfrom.name': 1,
          'contocomfrom.title': 1,
          'contocomto.path': 1,
          'contocomto.name': 1,
          'contocomto.title': 1,
        },
      },

    ];

    return aggr1;

  } catch (e) {
    return [];
  }

  return [];
};

MovementSchema.statics.getTotal_Transactions = async function (idapp) {
  const MyMovement = this;

  const numtransac = await MyMovement.countDocuments(
    {
      idapp,
    });

  return numtransac;

};

MovementSchema.statics.getTot_RIS_Transati = async function (idapp) {
  const MyMovement = this;

  // Utilizza l'aggregazione per sommare tutti gli 'amount' per un dato 'idapp'
  const numtot = await MyMovement.aggregate([
    {
      $match: { idapp }  // Filtra i documenti per 'idapp'
    },
    {
      $sort: {
        transactionDate: -1,
      }
    },
    {
      $group: {
        _id: null,
        totalAmount: { $sum: "$amount" }  // Somma tutti gli 'amount'
      }
    }
  ]);

  try {
    return numtot.length > 0 ? numtot[0].totalAmount : 0;
  } catch (e) {
    return 0;
  }


};

MovementSchema.statics.getMovsByCircuitId = async function (idapp, username, circuitId) {
  const MyMovement = this;

  const myquery = await MyMovement.getQueryMovsByCircuitId(idapp, username, '', '', circuitId);

  if (myquery && myquery.length > 0) {
    ris = await MyMovement.aggregate(myquery);

    return ris;
  }

  return [];
};

MovementSchema.statics.checkIfCoinsAlreadySent = async function (notifId) {
  const MyMovement = this;

  try {
    const rec = await MyMovement.findOne({ notifId }, { _id: 1 });
    return !!rec;

  } catch (e) {
    // If Error, don't send the coins
    return true;
  }

};

MovementSchema.statics.getLastN_Transactions = async function (idapp, numtransaz = 10, username = '', groupname = '', contocom = '') {
  const MyMovement = this;

  // get last "numtransaz" transactions

  let abilitaquerypersingolo = (username || groupname || contocom);

  let querym2 = null;

  if (abilitaquerypersingolo) {
    let v1 = [];

    if (username) {
      v1.push({ 'userfrom.username': username },
        { 'userto.username': username });
    }

    if (groupname) {
      v1.push({ 'groupfrom.groupname': groupname },
        { 'groupto.groupname': groupname });
    }
    if (contocom) {
      v1.push({ 'contocomfrom.name': contocom },
        { 'contocomto.name': contocom });
    }

    querym2 = {
      $match:
        { $or: v1 }
    };
  };


  let aggr1 = [
    {
      $match: { idapp },
    },
    {
      $sort: {
        transactionDate: -1,
      }
    },
    {
      $lookup: {
        from: 'accounts',
        localField: 'accountFromId',
        foreignField: '_id',
        as: 'accfrom',
      },
    },
    { $unwind: '$accfrom' },
    {
      $lookup: {
        from: 'users',
        let: { username: '$accfrom.username', idapp: '$accfrom.idapp' },
        pipeline: [
          {
            $match:
            {
              $expr:
              {
                $and:
                  [
                    { $eq: ['$$username', '$username'] },
                    { $eq: ['$$idapp', '$idapp'] },
                  ],
              },
            },
          },
        ],
        as: 'userfrom',
      },
    },
    {
      $unwind: {
        path: '$userfrom',
        preserveNullAndEmptyArrays: true,
      },
    },
    {
      $lookup: {
        from: 'mygroups',
        let: { groupname: '$accfrom.groupname', idapp: '$accfrom.idapp' },
        pipeline: [
          {
            $match:
            {
              $expr:
              {
                $and:
                  [
                    { $eq: ['$$groupname', '$groupname'] },
                    { $eq: ['$$idapp', '$idapp'] },
                  ],
              },
            },
          },
        ],
        as: 'groupfrom',
      },
    },
    {
      $unwind: {
        path: '$groupfrom',
        preserveNullAndEmptyArrays: true,
      },
    },

    {
      $lookup: {
        from: 'circuits',
        let: { contocom: '$accfrom.contocom', idapp: '$accfrom.idapp' },
        pipeline: [
          {
            $match:
            {
              $expr:
              {
                $and:
                  [
                    { $eq: ['$$contocom', '$path'] },
                    { $eq: ['$$idapp', '$idapp'] },
                  ],
              },
            },
          },
        ],
        as: 'contocomfrom',
      },
    },
    {
      $unwind: {
        path: '$contocomfrom',
        preserveNullAndEmptyArrays: true,
      },
    },
    {
      $lookup: {
        from: 'accounts',
        localField: 'accountToId',
        foreignField: '_id',
        as: 'accto',
      },
    },
    { $unwind: '$accto' },
    {
      $lookup: {
        from: 'circuits',
        localField: 'accfrom.circuitId',
        foreignField: '_id',
        as: 'circuitfrom',
      },
    },
    {
      $unwind: '$circuitfrom',
    },
    {
      $lookup: {
        from: 'circuits',
        localField: 'accto.circuitId',
        foreignField: '_id',
        as: 'circuitto',
      },
    },
    {
      $unwind: '$circuitto',
    },
    {
      $lookup: {
        from: 'users',
        let: { username: '$accto.username', idapp: '$accto.idapp' },
        pipeline: [
          {
            $match:
            {
              $expr:
              {
                $and:
                  [
                    { $eq: ['$$username', '$username'] },
                    { $eq: ['$$idapp', '$idapp'] },
                  ],
              },
            },
          },
        ],
        as: 'userto',
      },
    },
    {
      $unwind: {
        path: '$userto',
        preserveNullAndEmptyArrays: true,
      },
    },
    {
      $lookup: {
        from: 'mygroups',
        let: { groupname: '$accto.groupname', idapp: '$accto.idapp' },
        pipeline: [
          {
            $match:
            {
              $expr:
              {
                $and:
                  [
                    { $eq: ['$$groupname', '$groupname'] },
                    { $eq: ['$$idapp', '$idapp'] },
                  ],
              },
            },
          },
        ],
        as: 'groupto',
      },
    },
    {
      $unwind: {
        path: '$groupto',
        preserveNullAndEmptyArrays: true,
      },
    },
    {
      $lookup: {
        from: 'circuits',
        let: { contocom: '$accto.contocom', idapp: '$accto.idapp' },
        pipeline: [
          {
            $match:
            {
              $expr:
              {
                $and:
                  [
                    { $eq: ['$$contocom', '$path'] },
                    { $eq: ['$$idapp', '$idapp'] },
                  ],
              },
            },
          },
        ],
        as: 'contocomto',
      },
    },
    {
      $unwind: {
        path: '$contocomto',
        preserveNullAndEmptyArrays: true,
      },
    },
  ];

  if (querym2)
    aggr1.push(querym2);

  if (numtransaz)
    aggr1.push({ $limit: numtransaz });

  aggr1.push({
    $project:
    {
      transactionDate: 1,
      amount: 1,
      causal: 1,
      notifId: 1,
      'circuitfrom.symbol': 1,
      'circuitfrom.name': 1,
      'circuitto.symbol': 1,
      'circuitto.name': 1,
      'userfrom.verified_by_aportador': 1,
      'userfrom.username': 1,
      'userfrom.profile.img': 1,
      'userto.username': 1,
      'userto.profile.img': 1,
      'userto.verified_by_aportador': 1,
      'groupfrom.groupname': 1,
      'groupfrom.verified_by_aportador': 1,
      'groupfrom.title': 1,
      'groupfrom.photos': 1,
      'groupto.groupname': 1,
      'groupto.title': 1,
      'groupto.photos': 1,
      'groupto.verified_by_aportador': 1,
      'contocomfrom.path': 1,
      'contocomfrom.name': 1,
      'contocomto.path': 1,
      'contocomto.name': 1,
    },
  });

  const lastNtransac = await MyMovement.aggregate(aggr1);

  /* 
  transacDate: Date
  mitt_username: string
  mitt_group: string
  dest_username: string
  dest_group: string
  circuito: string
  amount: number
  causale: string
   
  */


  return lastNtransac;
};

const Movement = mongoose.model('Movement', MovementSchema);

Movement.createIndexes((err) => {
  if (err) throw err;
});

module.exports = { Movement };
