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

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

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

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

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

const MyGroupSchema = new Schema({
  _id: {
    type: String,
    default: function () {
      return new ObjectID().toString();
    },
  },
  idapp: {
    type: String,
  },
  groupname: {
    type: String,
  },
  title: {
    type: String,
  },
  descr: {
    type: String,
  },
  idCatGrp: {
    type: Number,
  },
  userId: {
    type: String,
  },
  photos: [
    {
      imagefile: {
        type: String,
      },
      alt: {
        type: String,
      },
      description: {
        type: String,
      },
    }],
  idCity: [
    {
      type: Number,
    }],
  website: {
    type: String,
  },
  link_telegram: {
    type: String,
  },
  note: {
    type: String,
    default: '',
  },
  //**ADDFIELD_MYGROUPS
  visibility: [
    {
      type: Number,
    },
  ],
  pwd_cryp: {
    type: String,
  },
  createdBy: {
    type: String,
  },
  admins: [
    {
      username: { type: String },
      perm: { type: Number },
      date: { type: Date },
    },
  ],
  blocked: {
    type: Boolean,
  },
  username_who_block: {
    type: String,
  },
  date_created: {
    type: Date,
  },
  date_updated: {
    type: Date,
  },
  date_blocked: {
    type: Date,
  },
  req_users: [
    {
      _id: false,
      username: { type: String },
      date: { type: Date },
    }],  // username
  refused_users: [
    {
      _id: false,
      username: { type: String },
      date: { type: Date },
    }],  // username
  deleted: {
    type: Boolean,
    default: false,
  },
  mycircuits: [
    {
      _id: false,
      circuitname: { type: String },
      date: { type: Date },
    }],
  lastdate_reqRisGroup: {
    type: Date,
  },
});

MyGroupSchema.statics.getFieldsForSearch = function () {
  return [{ field: 'descr', type: tools.FieldType.string }];
};

MyGroupSchema.statics.executeQueryTable = function (idapp, params, user) {
  params.fieldsearch = this.getFieldsForSearch();

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

  if (params.options) {
    if (tools.isBitActive(params.options, shared_consts.OPTIONS_SEARCH_USER_ONLY_FULL_WORDS)) {
      params.fieldsearch = User.getFieldsForSearchUserFriend();
    } else if (tools.isBitActive(params.options, shared_consts.OPTIONS_SEARCH_USER_ALL_WORDS)) {
      params.fieldsearch = User.getFieldsForSearchUserFriend_AllWords();
    }
  }

  return tools.executeQueryTable(this, idapp, params, user);
};

MyGroupSchema.pre('save', async function (next) {
  if (this.isNew) {
    if (!this.date_created)
      this.date_created = new Date();
  }

  next();
});

MyGroupSchema.statics.findAllIdApp = async function (idapp) {
  const myfind = { idapp };

  return await MyGroup.find(myfind);
};

MyGroupSchema.statics.findAllGroups = async function (idapp) {

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

  return await MyGroup.find({
    idapp,
    $or: [
      { deleted: { $exists: false } },
      { deleted: { $exists: true, $eq: false } }],
  }, whatToShow);
};

// Rimuovo la Richiesta del Gruppo
MyGroupSchema.statics.removeReqGroup = async function (idapp, username, groupnameDest) {

  return await MyGroup.updateOne({ idapp, groupname: groupnameDest },
    { $pull: { req_users: { username: { $in: [username] } } } });
};

// Aggiungi agli utenti Rifiutati del Gruppo
MyGroupSchema.statics.refuseReqGroup = async function (idapp, username, groupnameDest) {

  return await MyGroup.updateOne({ idapp, groupname: groupnameDest },
    {
      $push:
      {
        refused_users: {
          username,
          date: new Date(),
        },
      },
    });

};

// Aggiungi agli Admin del Gruppo
MyGroupSchema.statics.addToAdminOfMyGroup = async function (idapp, username, groupnameDest) {

  return await MyGroup.updateOne({ idapp, groupname: groupnameDest },
    {
      $push:
      {
        admins: {
          username,
          date: new Date(),
        },
      },
    });

};

// Rimuovi dagli Admin del Gruppo
MyGroupSchema.statics.removeAdminOfMyGroup = async function (idapp, username, groupnameDest) {

  return await MyGroup.updateOne({ idapp, groupname: groupnameDest },
    { $pull: { admins: { username: { $in: [username] } } } });
};

MyGroupSchema.statics.getListAdminsByGroupName = async function (idapp, groupname) {

  let arr = await MyGroup.findOne({
    idapp,
    groupname,
    $or: [
      { deleted: { $exists: false } },
      { deleted: { $exists: true, $eq: false } }],
  }, { admins: 1 }).lean();

  return arr && arr.admins ? arr.admins : [];

};

MyGroupSchema.statics.getWhatToShow = function (idapp, username) {
  // FOR ME, PERMIT ALL
  return {
    groupname: 1,
    title: 1,
    descr: 1,
    visibility: 1,
    idCatGrp: 1,
    userId: 1,
    photos: 1,
    idCity: 1,
    website: 1,
    //**ADDFIELD_MYGROUPS
    link_telegram: 1,
    note: 1,
    admins: 1,
    blocked: 1,
    req_users: 1,
    refused_users: 1,
    createdBy: 1,
    date_created: 1,
    date_updated: 1,
    mycircuits: 1,
    lastdate_reqRisGroup: 1,
  };

};

MyGroupSchema.statics.getWhatToShow_Unknown = function (idapp, username) {
  return {
    groupname: 1,
    title: 1,
    descr: 1,
    photos: 1,
    visibility: 1,
    idCatGrp: 1,
    idCity: 1,
    note: 1,
    date_created: 1,
    date_updated: 1,
    mycircuits: 1,
    lastdate_reqRisGroup: 1,
  };
};

MyGroupSchema.statics.getArrUsernameFromFieldByGroupname = async function (
  idapp, groupname, field) {

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

  const myobj = {};
  myobj[field + '.' + subfield] = 1;

  let arrrec = await User.findOne({
    idapp,
    groupname,
    $or: [{ deleted: { $exists: false } }, { deleted: { $exists: true, $eq: false } }],
  }, myobj).then((ris) => ris ? ris._doc[field] : []);

  if (arrrec.length > 0) {
    return arrrec.map(m => m.username);
  }
  return [];

};

MyGroupSchema.statics.getInfoGroupByGroupname = async function (idapp, groupname) {

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

  const myfind = {
    idapp,
    groupname,
  };

  const query = [
    { $match: myfind },
    { $unwind: '$mycircuits' },
    {
      $lookup: {
        from: 'circuits',
        localField: 'mycircuits.circuitname',
        foreignField: 'name',
        as: 'mycircuits',
      },
    },
    {
      '$replaceRoot': {
        'newRoot': {
          '$mergeObjects': [
            {
              '$arrayElemAt': [
                '$mycircuits',
                0,
              ],
            },
            '$$ROOT',
          ],
        },
      },
    },
    { $project: whatToShow },

  ];

  try {
    const ris = await MyGroup.aggregate(query);

    if (ris && ris.length > 0)
      return ris[0];
  } catch (e) {
    return null;
  }

  return ris;

};

MyGroupSchema.statics.deleteGroup = async function (idapp, usernameOrig, groupname) {
  console.log('Gruppo ' + groupname + ' rimosso da ' + usernameOrig);
  return await MyGroup.findOneAndRemove({ idapp, groupname });
};

MyGroupSchema.statics.getGroupsByUsername = async function (idapp, username, req) {

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

    const whatToShow = this.getWhatToShow(idapp, username);
    const whatToShow_Unknown = this.getWhatToShow_Unknown(idapp, username);
    const arrUsernameGroups = await User.getUsernameGroupsByUsername(idapp, username);
    // const arrUsernameReqGroups = await MyGroup.getUsernameReqGroupsByGroupname(idapp, username);

    let listUsersGroup = await User.find({
      idapp,
      username: { $in: arrUsernameGroups },
      $or: [
        { deleted: { $exists: false } },
        { deleted: { $exists: true, $eq: false } }],
    }, whatToShow);

    let listgroups = await MyGroup.find({
      idapp,
      $or: [
        { deleted: { $exists: false } },
        { deleted: { $exists: true, $eq: false } }],
    }, whatToShow_Unknown);

    /*let listRequestUsersGroup = await User.find({
      idapp,
      username: {$in: arrUsernameReqGroups},
      $or: [
        {deleted: {$exists: false}},
        {deleted: {$exists: true, $eq: false}}],
    }, whatToShow_Unknown);

     */

    let listSentRequestGroups = await MyGroup.find({
      idapp,
      'req_users': {
        $elemMatch: { username: { $eq: username } },
      },
      $or: [
        { deleted: { $exists: false } },
        { deleted: { $exists: true, $eq: false } }],
    }, whatToShow_Unknown);

    let listRefusedGroups = await MyGroup.find({
      idapp,
      'refused_users': {
        $elemMatch: { username: { $eq: username } },
      },
      $or: [
        { deleted: { $exists: false } },
        { deleted: { $exists: true, $eq: false } }],
    }, whatToShow_Unknown);

    return {
      listUsersGroup,
      listgroups,
      listSentRequestGroups,
      listRefusedGroups,
      mygroups: req.user.profile.mygroups,
    };

  } catch (e) {
    console.log('Error', e);
  }

  return {
    listUsersGroup: [],
    listRequestUsersGroup: [],
    listTrusted: [],
    listSentRequestGroups: [],
    listRefusedGroups: [],

  };
};

MyGroupSchema.statics.extractCitiesName = async function (idapp, id) {

  try {
    let aggr1 = [
      {
        $match: { idapp, _id: id },
      },
      {
        $lookup: {
          from: 'cities',
          localField: 'idCity',
          foreignField: '_id',
          as: 'mycities',
        },
      },
      {
        '$replaceRoot': {
          'newRoot': {
            '$mergeObjects': [
              {
                '$arrayElemAt': [
                  '$mycities',
                  0,
                ],
              },
              '$$ROOT',
            ],
          },
        },
      },
      {
        $project: {
          "mycities.comune": 1,
          "mycities.prov": 1
        },
      },
    ];

    ris = await this.aggregate(aggr1);

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

};

MyGroupSchema.statics.ifCircuitAlreadyInGroup = async function (idapp, groupname, circuitname) {

  // Controllo se è stato già inserito il circuito sul gruppo
  return await this.findOne({
    idapp,
    groupname,
    'mycircuits': {
      $elemMatch: { circuitname: { $eq: circuitname } },
    },
  }).lean();
};

// aggiungo il Circuito all'interno del Gruppo
MyGroupSchema.statics.addCircuitFromGroup = async function (idapp, groupname, circuitname) {
  return await this.updateOne({ idapp, groupname },
    {
      $push: {
        'mycircuits': {
          circuitname,
          date: new Date(),
        }
      }
    });

};

// Rimuovo il Circuito all'interno del Gruppo
MyGroupSchema.statics.removeCircuitFromGroup = async function (idapp, groupname, circuitname) {
  return await this.updateOne({ idapp, groupname },
    { $pull: { 'mycircuits': { circuitname: { $in: [circuitname] } } } });

};

MyGroupSchema.statics.getQueryReceiveRISGroups = function (idapp, hours) {

  const query = [
    {
      $match: {
        idapp,
        'lastdate_reqRisGroup': { $gte: tools.IncDateNow(-(1000 * 60 * 60 * hours)) },
        $or: [
          { deleted: { $exists: false } },
          { deleted: { $exists: true, $eq: false } }],
      },
    },
    {
      $group:
      {
        _id: "$groupname",
        count: {
          $sum: 1,
        },
      }
    },
    { $sort: { 'lastdate_reqRisGroup': -1 } },
    { $limit: 30 },
    {
      $lookup: {
        from: "mygroups",
        let: {
          groupname: "$_id",
          idapp,
        },
        pipeline: [
          {
            $match: {
              $expr: {
                $and: [
                  {
                    $eq: [
                      "$$groupname",
                      "$groupname",
                    ],
                  },
                  {
                    $eq: [
                      "$$idapp",
                      "$idapp",
                    ],
                  },
                ],
              },
            },
          },
        ],
        as: "mygroup",
      },
    },
    { $unwind: "$mygroup" },
    {
      $replaceRoot: {
        newRoot: {
          $mergeObjects: ["$mygroup", "$$ROOT"],
        },
      },
    },
    {
      $project: {
        _id: 0,
        groupname: 1,
        title: 1,
        descr: 1,
        visibility: 1,
        idCatGrp: 1,
        userId: 1,
        photos: 1,
        idCity: 1,
        website: 1,
        link_telegram: 1,
        note: 1,
        admins: 1,
        blocked: 1,
        req_users: 1,
        createdBy: 1,
        date_created: 1,
        date_updated: 1,
        lastdate_reqRisGroup: 1,
      },
    },
  ];
  return query;
};


MyGroupSchema.statics.getReceiveRISGroups = async function (idapp) {

  return await this.aggregate(this.getQueryReceiveRISGroups(idapp, 8)).then(ris => {
    return ris;
  });

};

MyGroupSchema.statics.setReceiveRisGroup = async function (idapp, groupname) {

  return await this.findOneAndUpdate({
    idapp, groupname,
  },
    { $set: { 'lastdate_reqRisGroup': new Date() } }, { new: false }).lean().then((record) => {
      return !!record;
    });

};



const MyGroup = mongoose.model('MyGroup', MyGroupSchema);

module.exports = { MyGroup };
