const mongoose = require('mongoose');
const _ = require('lodash');

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

const { ListaIngresso } = require('./listaingresso');
const { NavePersistente } = require('./navepersistente');
const { Settings } = require('./settings');
const { User } = require('./user');

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

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

mongoose.set('debug', process.env.DEBUG);


const NaveSchema = new mongoose.Schema({
  idapp: {
    type: String,
    required: true,
  },
  riga: {
    type: Number,
  },
  col: {
    type: Number,
  },
  ind_order: {
    type: Number,
  },
  parent_id: {
    type: mongoose.Schema.Types.ObjectId,
  },
  sent_msg_howto_make_gift: {
    type: Boolean,
    default: false,
  },
  made_gift: {
    type: Boolean,
    default: false,
  },
  date_made_gift: {
    type: Date,
  },
  received_gift: {
    type: Boolean,
    default: false,
  },
  date_received_gift: {
    type: Date,
  },
  created: {
    type: Date,
  },
  num_tess: {  // numero di tessitura
    type: Number,
    default: 1
  },
  note: {
    type: String
  },
});

NaveSchema.statics.getTotInLista = async function (idapp) {
  const Nave = this;

  const myfind = { idapp };

  return await Nave.count(myfind);
};

NaveSchema.statics.findByIndOrder = function (idapp, ind_order) {
  const Nave = this;

  try {
    return Nave.findOne({
      'idapp': idapp,
      'ind_order': ind_order,
    });
  } catch (e) {

  }
};

NaveSchema.statics.checkIfNaveExist = async function (idapp, username) {
  const Nave = this;

  try {

    const arrlista = await ListaIngresso.find({
      idapp,
      username,
      // added: true,
      deleted: false,
    });

    for (const rec of arrlista) {
      const mynave = await Nave.find({ idapp, ind_order: rec.ind_order });
      if (!!mynave)
        return true;
    }

    return false;

  } catch (e) {

  }
};

NaveSchema.statics.findByIndOrderAndNumTess = function (idapp, ind_order, num_tess) {
  const Nave = this;

  try {
    return Nave.findOne({
      idapp,
      ind_order,
      num_tess,
    });
  } catch (e) {

  }
};

NaveSchema.statics.findById = function (idapp, id) {
  const Nave = this;

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

  const myquery = getQueryProj({ idapp, '_id': id });

  return Nave.aggregate(myquery)
    .then(async (rec) => {
      try {
        if (!!rec) {
          if (rec.length > 0) {
            const ris = await User.findByIndOrder(idapp, rec[0].ind_order);
            if (!!ris) {
              if (!!ris._doc)
                rec[0] = { ...rec[0], ...ris._doc };
              else
                rec[0] = { ...rec[0], ...ris };
              return rec[0];
            }
            return rec[0];
          } else {
            return null;
          }
        } else {
          return null;
        }
      }catch (e) {
        console.error(e.message);
      }
    });

};


NaveSchema.statics.getFieldsForSearch = function () {
  return [{ field: 'ind_order', type: tools.FieldType.number },
    { field: 'riga', type: tools.FieldType.number },
    { field: 'col', type: tools.FieldType.number },
    { field: '_id', type: tools.FieldType.exact }]
};

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

NaveSchema.statics.findAllIdApp = function (idapp) {
  const Nave = this;

  const myfind = { idapp };

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

NaveSchema.statics.findByRigaCol = function (idapp, riga, col, nullifnotexist) {
  const Nave = this;

  myrigacol = {
    idapp,
    riga,
    col,
    nullifnotexist
  };

  return Nave.findGeneric(myrigacol);

};

NaveSchema.statics.findDonatoreByNave = function (idapp, nave) {
  try {

    const arrrigacol = nave.split(".");
    if (arrrigacol.length <= 0)
      return;

    let riganave = parseInt(arrrigacol[0]);
    let colnave = parseInt(arrrigacol[1]);

    let rigadonatore = riganave + 3;
    if (rigadonatore < 1)
      rigadonatore = 1;

    coldonatoreIni = calcval(riganave, colnave, 8) + (1);
    coldonatoreFine = calcval(riganave, colnave, 8) + (8);

    const miaquery = {
      idapp,
      riga: rigadonatore,
      $and: [{ col: { $gte: { coldonatoreIni } } }, { col: { $lte: { coldonatoreFine } } }]
    };

    return Nave.findOne(miaquery);
  } catch (e) {
    console.error(e.message);
  }
};

function getIndColonneByNave(navemediatore) {
  let riga = navemediatore.riga;
  let col = navemediatore.col;

  let col_ini = calcval(riga, col, 8) + 1;
  let col_fine = col_ini + 7;

  return { riga: riga + 3, col_ini, col_fine }
}

NaveSchema.statics.getusersByNave = function (idapp, navemediatore) {

  if ((!navemediatore.riga) || (!navemediatore.col))
    return [];

  const obj = getIndColonneByNave(navemediatore);

  const miacol_ini = obj.col_ini;
  const miacol_fine = obj.col_fine;

  const miaquery = {
    idapp,
    riga: obj.riga,
    $and: [
      { col: { $gte: miacol_ini } },
      { col: { $lte: miacol_fine } }
    ],
  };

  return Nave.find(miaquery);

};


NaveSchema.statics.findRecByRigaColParent = async function (idapp, riga, col, numparentUp) {
  const Nave = this;

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

  const myrigacol = {
    idapp,
    riga,
    col
  };

  if (numparentUp === 0) {
    return await Nave.findGeneric(myrigacol);
  }

  let parentup = 0;
  let myrec = null;
  let lastrec = null;

  while (parentup < numparentUp) {

    myrec = await Nave.findGeneric(myrigacol);
    if (!!myrec) {
      if (myrec.parent_id === "0") {
        break;
      }

      recfind = await Nave.findById(idapp, myrec.parent_id);
      if (!!recfind) {
        lastrec = recfind;
        myrigacol.riga = lastrec.riga;
        myrigacol.col = lastrec.col;
      } else {
        //lastrec = await User.findByIndOrder(idapp, 0);
        lastrec = await Nave.findGeneric({ idapp, riga: 0, col: 0 });
        break;
      }
    }
    parentup++;
  }

  if (!lastrec) {
    // return await User.findByIndOrder(idapp, 0);
    return await Nave.findGeneric({ idapp, riga: 0, col: 0 });
  }

  return lastrec;

};


NaveSchema.statics.findGeneric = function (myrigacol) {

  const { ListaIngresso } = require('./listaingresso');

  const myquery = getQueryProj({ idapp: myrigacol.idapp, riga: myrigacol.riga, col: myrigacol.col });

  return Nave.aggregate(myquery)
    .then(async (rec) => {
        if (!rec || rec.length === 0) {
          if (myrigacol.nullifnotexist)
            return null;

          const ris = await ListaIngresso.findByIndOrder(myrigacol.idapp, 0);
          const arr = [];
          arr.push(ris);
          return arr;
        }
        else {
          return rec;
        }
      }
    ).then(async (rec) => {

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

      if (!!rec) {
        if (rec.length > 0) {
          // console.log('rec', rec);
          // console.table('myrigacol', myrigacol);
          if (!!rec[0]) {
            const newrec = await User.getSmallRecByIndOrder(myrigacol.idapp, rec[0].ind_order);
            if (!!newrec) {
              let myarr = {};
              if (rec[0]._doc === undefined)
                myarr = { ...newrec, ...rec[0] };
              else
                myarr = { ...newrec, ...rec[0]._doc };
              return myarr;
            } else {
              let myarr = rec[0];
              if (!!newrec) {
                if (rec[0]._doc === undefined)
                  myarr = { ...newrec, ...rec[0] };
                else
                  myarr = { ...newrec, ...rec[0]._doc };
              }
              return myarr;
            }
          } else {
            const ris = await ListaIngresso.findByIndOrder(myrigacol.idapp, 0);
            if (!!ris)
              return ris[0]
          }
        }
      }
      return null;
    }).catch((e) => {
      console.error(e.message);
    });

}
;


NaveSchema.statics.findSognatoriByFuoco = async function (idapp, riga, col, offset) {
  const Nave = this;

  // const myrigacol = getRigaColSognatoreByFuoco(idapp, riga, col);

  // return Nave.findGeneric(myrigacol);

  return [await Nave.findRecByRigaColParent(idapp, riga, col, 6 - offset),
    await Nave.findRecByRigaColParent(idapp, riga, col, 5 - offset),
    await Nave.findRecByRigaColParent(idapp, riga, col, 4 - offset)
  ]

};


NaveSchema.statics.findMediatoreByFuoco = async function (idapp, riga, col, offset) {
  const Nave = this;

  // const myrigacol = getRigaColMediatoreByFuoco(idapp, riga, col);
  // return Nave.findGeneric(myrigacol);
  return await Nave.findRecByRigaColParent(idapp, riga, col, 3 - offset);

};

function getQueryProj(myfilter) {

  myobjField = {
    _id: 1,
    idapp: 1,
    lang: 1,
    ind_order: 1,
    name: 1,
    surname: 1,
    username: 1,
    invitante_username: 1,
    deleted: 1,
    sospeso: 1,
    'profile.paymenttypes': 1,
    'profile.teleg_id': 1,
    'profile.email_paypal': 1,
    'profile.cell': 1,
    made_gift: 1,
    sent_msg_howto_make_gift: 1,
    date_made_gift: 1,
    note: 1,
    received_gift: 1,
    date_received_gift: 1,
    num_tess: 1,
    parent_id: 1,
    riga: 1,
    col: 1,
    created: 1,
    // date_start: 1,
    // date_gift_chat_open: 1,
    // link_chat: 1,
    // provvisoria: 1,
    // note_bot: 1,
    // note_interne: 1,
    // tutor: 1,
    // tutor_namesurname: 1,
  };

  const query = [
    { $match: myfilter },
    {
      $lookup: {
        from: "listaingressos",
        localField: "ind_order",
        foreignField: "ind_order",      // field in the user collection
        as: "mylista"
      }
    },
    {
      $unwind: "$mylista"
    },
    {
      $lookup: {
        from: "users",
        as: "user",
        let: {username: '$mylista.username' },
        pipeline: [
          {
            $match: {
              $expr: {
                $and: [
                  { $eq: ['$username', '$$username'] },
                  { $eq: ['$idapp', myfilter.idapp] },
                ]
              }
            }
          }
        ]
      }
    },
    {
      $replaceRoot: { newRoot: { $mergeObjects: [{ $arrayElemAt: ["$user", 0] }, "$$ROOT"] } }
      // $replaceRoot: { newRoot: { $mergeObjects: [{ $arrayElemAt: ["$user", 0] },] } }
    },
    { $match: { $or: [{ deleted: { $exists: false } }, { deleted: { $exists: true, $eq: false } }] } },
    { $project: myobjField }
  ];

  return query;
}


NaveSchema.statics.setRiga = function (idapp, riga) {
  return Settings.setKeyNum(idapp, 'riga', riga);
};

NaveSchema.statics.getRiga = function (idapp) {
  return Settings.getKeyNum(idapp, 'riga', 1);
};

NaveSchema.statics.setCol = function (idapp, col) {
  return Settings.setKeyNum(idapp, 'col', col);
};

NaveSchema.statics.getCol = function (idapp) {
  return Settings.getKeyNum(idapp, 'col', 1);
};

function getmaxcol(riga) {

  return Math.pow(2, riga - 1);
}

function getPrimoFuocoByIndCol(col) {
  // let ris = Math.ceil(col - (col % 8)) + 1;
  let ris = ((Math.ceil(col / 8) - 1) * 8) + 1;
  if (ris <= 0)
    ris = 1;
  return ris
}

async function getusertextbyrec(myrec, symbol, lettera, riga, col, ind) {
  let visu_test = false;
  if (!!myrec)
    visu_test = await Settings.getValDbSettings(myrec.idapp, 'VISU_TEST');

  if (!visu_test) {
    if (myrec)
      return lettera + ind + ' - ' + symbol + ' ' + myrec.name + ' ' + tools.getFirst2Car(myrec.surname) + ' (' + myrec.username + ')';
    else
      return lettera + ind + ' - ' + symbol;

  } else {
    if (myrec)
      return lettera + ind + ' - ' + symbol + '[' + riga + ',' + col + ']' + ' ' + myrec.name + ' ' + myrec.surname + '';
    else
      return lettera + ind + ' - ' + symbol;
  }
}

function checkifNullThenEmpty(rec, riga, col) {
  if (rec === null) {
    return {
      name: '',
      surname: '',
      username: '',
      riga,
      col,
    }
  } else {
    return rec;
  }
}

NaveSchema.statics.getPlaccaGenerica = async function (idapp, riga, col, offset, solorecord) {
  const Nave = this;

  try {
    let recsognatori = await Nave.findSognatoriByFuoco(idapp, riga, col, offset);
    let recmediatore = await Nave.findMediatoreByFuoco(idapp, riga, col, offset);
    let navepersistente = await NavePersistente.findByRigaColByDonatore(idapp, riga, col, offset);

    if (!solorecord) {
      mystr = tools.ACAPO;

      mystr += 'GIFTING CHAT (' + riga + '.' + col + ') ' + tools.ACAPO + tools.ACAPO;

      if (offset === tools.Placca.SONOFUOCO) {
        mystr += tools.Placca.SOGNATORE + tools.Placca.STR_SOGNATORE + ': ' + await getusertextbyrec(recsognatori[0], '', '', riga, col, '') + tools.ACAPO + tools.ACAPO;
        mystr += tools.Placca.MEDIATORE + tools.Placca.STR_MEDIATORE + ': ' + await getusertextbyrec(recmediatore, '', '', riga, col, '') + tools.ACAPO + tools.ACAPO;
      }

      if (offset === tools.Placca.SONOACQUA) {
        mystr += tools.Placca.SOGNATORE + tools.Placca.STR_SOGNATORE + ': ' + await getusertextbyrec(recmediatore, '', '', riga, col, '') + tools.ACAPO + tools.ACAPO;
      }

      let symb = {
        car: 'D',
        icona: '🔥'
      };

      if (offset === tools.Placca.SONOFUOCO) {
        mystr += tools.Placca.STR_DONATORI + ':' + tools.ACAPO;
      } else if (offset === tools.Placca.SONOACQUA) {
        mystr += tools.Placca.STR_MEDIATORI + ':' + tools.ACAPO;
        symb = {
          car: 'A',
          icona: '💦'
        };
      }
    }

    // mystr += '🔥🌏💦💨🔥🌏💦💨' + tools.ACAPO;

    let arrdonatori = [];
    // let numcol = Math.pow(2, indriga - 1);
    let primofuoco = getPrimoFuocoByIndCol(col * Math.pow(2, offset));

    let ind = 1;
    for (let indcol = primofuoco; indcol < primofuoco + 8; indcol++) {
      let indr = riga + offset;
      let indc = indcol + (offset * indr);

      indr = riga + offset;
      // indc = calcval(riga, col, 8) + (indcol - primofuoco + 1);
      if (offset === 0)
        indc = indcol;
      else
        indc = indcol;
      // miacol = calcval(riga, col, 8) + (indfuoco);


      let recfuoco = await Nave.findByRigaCol(idapp, indr, indc, true);
      recfuoco = checkifNullThenEmpty(recfuoco, indr, indc);
      arrdonatori.push({ index: ind, ...recfuoco });

      if (!solorecord) {
        mystr += await getusertextbyrec(recfuoco, symb.icona, symb.car, indr, indc, ind) + tools.ACAPO;
      }
      ind++;
    }

    if (solorecord) {
      res = {
        recsognatori,
        recmediatore,
        navepersistente,
        arrdonatori
      };

      return res;
    } else {
      return mystr;
    }

  } catch (e) {
    console.error(e.message);
  }

};

NaveSchema.statics.getPlaccaPerDonatore = async function (idapp, riga, col, solorecord, rec) {
  const Nave = this;

  if (solorecord) {

    rec.donatore = await Nave.getPlaccaGenerica(idapp, riga, col, tools.Placca.SONOFUOCO, solorecord);
    newcol = Math.ceil(col / (Math.pow(2, 3)));
    rec.donatore.arrterra = await Nave.getArrTerra(idapp, riga - 3, newcol);
    rec.donatore.arraria = await Nave.getArrAria(idapp, riga - 3, newcol);

    return rec;
  } else {
    return await Nave.getPlaccaGenerica(idapp, riga, col, tools.Placca.SONOFUOCO, solorecord);
  }


};

NaveSchema.statics.getPlaccaPerMediatore = async function (idapp, riga, col, solorecord, rec) {
  const Nave = this;
  rec.mediatore = await Nave.getPlaccaGenerica(idapp, riga, col, tools.Placca.SONOACQUA, solorecord);
  rec.mediatore.navepersistente = await NavePersistente.findByRigaColByDonatore(idapp, riga, col, -tools.Placca.SONOACQUA);

  rec.mediatore.arrterra = await Nave.getArrTerra(idapp, riga, col);
  rec.mediatore.arraria = await Nave.getArrAria(idapp, riga, col);

  return rec;
};

NaveSchema.statics.getArrTerra = async function (idapp, riga, col) {
  const Nave = this;

  let arrterra = [];
  for (let indterra = 1; indterra <= 2; indterra++) {
    miacol = calcval(riga, col, 2) + (indterra);
    miariga = riga + 1;
    let rec = await Nave.findByRigaCol(idapp, miariga, miacol, true);
    rec = checkifNullThenEmpty(rec, miariga, miacol);
    arrterra.push(rec);
  }

  return arrterra;
};

NaveSchema.statics.getArrAria = async function (idapp, riga, col) {
  const Nave = this;

  let arraria = [];
  for (let indaria = 1; indaria <= 4; indaria++) {
    miacol = calcval(riga, col, 4) + (indaria);
    miariga = riga + 2;
    let rec = await Nave.findByRigaCol(idapp, miariga, miacol, true);
    rec = checkifNullThenEmpty(rec, miariga, miacol);
    arraria.push(rec);
  }

  return arraria;

};

function calcval(riga, col, quanti) {
  return (quanti * (col - 1));
}

NaveSchema.statics.getNavePos = async function (idapp, riga, col, solorecord, ind_order) {
  const Nave = this;

  if (riga <= 0)
    riga = 1;
  if (col <= 0)
    col = 1;

  let lang = 'it';

  if (!!ind_order) {
    const { User } = require('./user');
    lang = await User.getLangByIndOrder(idapp, ind_order);
  }

  try {
    let recsognatori = [await Nave.findRecByRigaColParent(idapp, riga, col, 3),
      await Nave.findRecByRigaColParent(idapp, riga, col, 2),
      await Nave.findRecByRigaColParent(idapp, riga, col, 1)];

    let recmediatore = await Nave.findByRigaCol(idapp, riga, col, true);
    let recnavepersistente = await NavePersistente.findByRigaCol(idapp, riga, col, 0);


    mystr = '🌈' + tools.get__('SOGNATORE', lang) + ': ';
    for (let indsogn = 0; indsogn < recsognatori.length; indsogn++) {
      mystr += 'A' + (3 - indsogn) + await getusertextbyrec(recsognatori[indsogn], '', '', riga, col, '') + tools.ACAPO;
    }

    mystr += tools.ACAPO + '🌀 ' + tools.get__('MEDIATORE', lang) + ':' + await getusertextbyrec(recmediatore, '', '', riga, col, '') + tools.ACAPO + tools.ACAPO;

    for (let indterra = 1; indterra <= 2; indterra++) {
      miacol = calcval(riga, col, 2) + (indterra);
      miariga = riga + 1;
      let recterra = await Nave.findByRigaCol(idapp, miariga, miacol, true);
      mystr += await getusertextbyrec(recterra, '', 'B', miariga, miacol, indterra) + tools.ACAPO;
    }

    mystr += tools.ACAPO;

    for (let indaria = 1; indaria <= 4; indaria++) {
      miacol = calcval(riga, col, 4) + (indaria);
      miariga = riga + 2;
      let recaria = await Nave.findByRigaCol(idapp, miariga, miacol, true);
      mystr += await getusertextbyrec(recaria, '', 'C', miariga, miacol, indaria) + tools.ACAPO;
    }

    mystr += tools.ACAPO;

    let primofuoco = null;

    mystr += '🎁 ' + tools.get__('DONATORI', lang) + ':' + tools.ACAPO;
    let donitotali = 0;
    let donifatti = 0;

    for (let indfuoco = 1; indfuoco <= 8; indfuoco++) {
      miacol = calcval(riga, col, 8) + (indfuoco);
      miariga = riga + 3;
      // miariga = riga + 2;
      let recfuoco = await Nave.findByRigaCol(idapp, miariga, miacol, true);
      if (indfuoco === 1)
        primofuoco = recfuoco;

      if (!!recfuoco) {
        let symbol = '';
        if (recfuoco.made_gift) {
          symbol = '🎁';
          donifatti++;
        }
        if (!!recfuoco && recmediatore) {
          if (recfuoco.ind_order === recmediatore.ind_order && recfuoco.num_tess === 2) {
            mystr += await getusertextbyrec(recfuoco, '', tools.get__('RITESSITURA', lang), miariga, miacol, '') + tools.ACAPO;
          } else {
            mystr += await getusertextbyrec(recfuoco, symbol, 'D', miariga, miacol, indfuoco) + tools.ACAPO;
            donitotali++;
          }
        }
      }
    }

    if (donitotali > 0 && donifatti >= donitotali) {
      mystr += tools.ACAPO + '💫💫💫💫💫💫💫💫💫💫💫💫💫💫💫💫💫💫' + tools.ACAPO +
        '✨✨✨ ' + tools.get__('NAVE COMPLETATA', lang) + ' ' + ' (' + tools.get__('Doni Effettuati', lang) + ') ! ✨✨✨' + tools.ACAPO +
        '💫💫💫💫💫💫💫💫💫💫💫💫💫💫💫💫💫💫' + tools.ACAPO;
    }

    let data = "";
    let mystrtemp = '';
    if (primofuoco) {

      // tools.gettranslate('PLACCA_TUTOR', lang)

      if (!!recnavepersistente.tutor_namesurname)
        data += '👤 ' + tools.get__('Tutor che affianchèra il Mediatore', lang) + ': "' + recnavepersistente.tutor_namesurname + '"' + tools.ACAPO;

      data += '💬 ' + tools.get__('Giorno di Apertura GIFT CHAT', lang) + ': ' + tools.getstrDateLong(recnavepersistente.date_gift_chat_open, lang) + tools.ACAPO;

      data += '🎁 ' + tools.get__('Giorno in cui Inviare il DONO', lang) + ' : ' + tools.getstrDateLong(recnavepersistente.date_start, lang) + tools.ACAPO;
      if (!!recnavepersistente.note_bot)
        data += tools.get__('Note', lang) + ": " + recnavepersistente.note_bot + tools.ACAPO;

      if (recnavepersistente.provvisoria)
        mystrtemp = tools.get__('TEMPORANEA', lang) + ' ';
    } else
      data = "";


    mystr = tools.ACAPO + tools.get__('NAVE', lang) + ' ' + '[' + riga + '.' + col + '] ' + mystrtemp + tools.ACAPO + data + tools.ACAPO + mystr;

    return mystr;
  } catch (e) {
    console.error(e.message);
    return '';
  }

};

// async function Fuochi8Completati(idapp, params) {
//   // Inviare un msg al Mediatore che può aprire la Chat con gli 8 fuochi
//   const telegrambot = require('../telegram/telegrambot');
//
//   let text = '\nCompletata NAVE [riga=' + params.riga + ',col=' + params.col + ', ind_order=' + params.ind_order + ']';
//   console.log(text);
//   tools.writeNaveLog(text);
//
//   const { User } = require('./user');
//
//   const rec = await User.findByIndOrder(idapp, params.ind_order);
//
//   text = await Nave.getNaveByUser(idapp, params.ind_order, rec.lang, true);
//
//   // Inviare un msg a questi 8 Fuochi, che la loro placca è Pronta !
//
//   if (tools.isAbilitaNave(idapp)) {
//     // .............
//   }
//
//   if (false) {
//     await telegrambot.sendMsgTelegram(idapp, rec.username, text, true);
//   } else {
//     await telegrambot.sendMsgTelegramToTheAdmin(idapp, text);
//   }
//
//   // Inviare la placca a Managers
//   // await telegrambot.sendMsgTelegramToTheManagers(idapp, txt);
// }

NaveSchema.statics.getArrPosizioniByIndOrder = async function (idapp, ind_order) {
  const Nave = this;


  arrposizioni = await Nave.find({ idapp, ind_order }).sort({ riga: 1, col: 1 });

  return arrposizioni;
};

NaveSchema.statics.getArrPosizioniByUsername = async function (idapp, username) {
  const Nave = this;

  const { ListaIngresso } = require('./listaingresso');

  try {
    const arrrec_indorder = await ListaIngresso.findByAllRecByUsername(idapp, username).distinct("ind_order");

    let arrposizioni = [];

    for (const ind_order of arrrec_indorder) {
      const arr = await Nave.find({ 'idapp': idapp, ind_order }).sort({ riga: 1, col: 1 });
      if (!!arr)
        arrposizioni = [...arrposizioni, ...arr];
    }

    return arrposizioni;
  } catch (e) {
    console.error(e.message);
  }

};

NaveSchema.statics.getArrProfiliByIndOrder = async function (idapp, ind_order) {
  const Nave = this;

  arrposizioni = await Nave.find({ 'idapp': idapp, ind_order }).sort({ riga: 1, col: 1 });

  arrprofili = [];

  // Ind_Order
  // Ind_order_base


  return arrprofili;
};

NaveSchema.statics.getPrimaNaveByRiga = async function (idapp, riga) {
  const Nave = this;

  nave = await Nave.findOne({ 'idapp': idapp, riga: (riga + 3), col: 1 });

  return nave;
};

NaveSchema.statics.showListaOrd = async function (idapp) {
  const Nave = this;

  const myquery = getQueryProj({ idapp });

  arrrec = await Nave.aggregate(myquery).sort({ riga: 1, col: 1 });

  let mystr = '';
  let conta = 1;
  for (const rec of arrrec) {
    let recnavepersistente = await NavePersistente.findByRigaColByDonatore(idapp, rec.riga, rec.col, 0);
    if (!!recnavepersistente) {
      mystr += '[' + conta + '] [' + rec.riga + '.' + rec.col + '] ' + rec.ind_order + ' ' + rec.name + ' ' + rec.surname + ' (' + tools.getstrDateShort(recnavepersistente.date_start) + ')';
      mystr += ' num_tess = ' + rec.num_tess;
      mystr += '\n';
    }
    conta++;
  }


  return mystr;
};

NaveSchema.statics.getLastRigaCol = async function (idapp) {
  return Nave.findOne({ idapp }).sort({ _id: -1 });
};

async function addRecordNaveByParams(params, siRitesse) {
  const { ListaIngresso } = require('./listaingresso');

  let paramspers = { ...params };

  let mypos = {
    idapp: params.idapp,
    riga: params.riga,
    col: params.col,
    numup: 3
  };
  tools.getRigaColByPosUp(mypos);

  paramspers.riga1don = params.riga;
  paramspers.col1don = params.col;
  paramspers.riga = mypos.riga;
  paramspers.col = mypos.col;

  await NavePersistente.addRecordNavePersistenteByParams(paramspers);

  if (!siRitesse) {
    // Check if Exist:
    const giapresente = await Nave.findOne({
      idapp: params.idapp,
      ind_order: params.ind_order,
      num_tess: params.num_tess
    });
    if (!!giapresente) {
      let fields_to_update = { added: true };
      await ListaIngresso.findOneAndUpdate({ _id: params.id.toString() }, { $set: fields_to_update }, { new: false });

      return false;
    }
  }


  let myNave = new Nave({
    idapp: params.idapp,
    ind_order: params.ind_order,
    riga: params.riga,
    col: params.col,
    num_tess: params.num_tess,
  });
  myNave.created = new Date();

  // console.log('[' + params.riga + ',' + params.col + ']');
  // console.log('parent = [' + params.rigaparent + ',' + params.colparent + ']');

  const recfindparent = await Nave.findByRigaCol(idapp, params.rigaparent, params.colparent, false);

  // console.log('recfindparent = [' + recfindparent + ']');
  // console.table(recfindparent);
  if (!!recfindparent) {
    myNave.parent_id = recfindparent._id;
  } else {
    myNave.parent_id = "0";
  }

  console.log('addRecordNaveByParams (' + myNave.parent_id + ')');

  return await myNave.save()
    .then(async (result) => {

      if (!!result) {

        let fields_to_update = { added: true };
        await ListaIngresso.findOneAndUpdate({ _id: params.id.toString() }, { $set: fields_to_update }, { new: false });

        params.conta++;

        // Check if the Ship has Completed
        if (idapp === tools.AYNI) {
          if ((params.col % 8) === 0) {
            // Completed 8 people
            if (!params.primavolta) {
              // await Fuochi8Completati(idapp, params);
            }
          }
        }

        // Next
        if (params.col === params.maxcol) {
          params.riga++;
          params.rigaparent = params.riga - 1;
          params.col = 1;
          params.maxcol = getmaxcol(params.riga);
        } else {
          params.col++;
        }

        if (params.riga === 2)
          params.colparent = 1;
        else
          params.colparent = Math.ceil(params.col / 2);

        await Nave.setRiga(idapp, params.riga);
        await Nave.setCol(idapp, params.col);

        return true;
      }

      return false;

    }).catch((e) => {
      console.error(e.message);
    });
}

NaveSchema.statics.checkifDeveRitessersi = async function (recuser) {
  const Nave = this;

  let deveritessersi = true;

  arrrec = await Nave.find({ idapp: recuser.idapp, ind_order: recuser.ind_order, num_tess: recuser.num_tess });

  if (!!arrrec) {
    if ((arrrec.length % 2) === 0) {
      // deveritessersi = await User.deveRitessersi(recuser.idapp, recuser.ind_order)
      deveritessersi = false;
    }
  }

  return { deveritessersi, num_tess: arrrec.length };

};


NaveSchema.statics.addUserFromListaIngresso_IntoNave = async function (init, idapp, params, addednowreal) {
  const Nave = this;

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

  if (init) {
    params.idapp = idapp;
    params.conta = 0;
  }

  params.primavolta = (params.riga === 1) && (params.col === 1);
  params.riga = await Nave.getRiga(idapp);
  params.col = await Nave.getCol(idapp);
  params.maxcol = getmaxcol(params.riga);
  params.colparent = Math.ceil(params.col / 2);
  params.rigaparent = params.riga - 1;

  if (params.rigaparent === 0)
    params.colparent = 0;

  myriga = params.riga;
  mycol = params.col;

  const inserito = await addRecordNaveByParams(params, false);
  if (inserito) {
    if (idapp === tools.AYNI) {
      if (((params.col) % 8) === 0) {
        let recmediatore = await Nave.findMediatoreByFuoco(idapp, myriga, mycol, 0);
        if (!!recmediatore) {
          const ris = await Nave.checkifDeveRitessersi(recmediatore);
          if (ris.deveritessersi) {
            console.log('Si deve ritessere: [riga=', params.riga, 'col', params.col, ']');
            if (ris.deveritessersi) {
              params.ind_order = recmediatore.ind_order;
              params.id = recmediatore._id;
              params.num_tess = recmediatore.num_tess + 1;

              await addRecordNaveByParams(params, true);
            }
          }
        }
      }
      if ((params.riga === 4 + 3) && (params.col === (8 * 2) + 3)) {
        // Si ritesse il Fondo AYNI nella Nave 3.3
        const userFondo = await User.findByIndOrder(idapp, 0);
        params.ind_order = userFondo.ind_order;
        params.id = userFondo._id;
        params.num_tess = userFondo.num_tess;

        await addRecordNaveByParams(params, true);
      }
    }
  }

  // Se ho completato 8 persone, allora
  if (addednowreal) {

  }

};

NaveSchema.statics.generaNave = async function (idapp, mydata) {
  const Nave = this;

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

  let params = {
    idapp,
    riga: await Nave.getRiga(idapp),
    col: await Nave.getCol(idapp),
    date_start: mydata.date_start,
    date_gift_chat_open: tools.AddDate(mydata.date_start, -7),
    numpersone: mydata.numpersone,
  };

  params.primavolta = (params.riga === 1) && (params.col === 1);
  // params.primavolta = false;

  const recfindFondo = await Nave.findByRigaCol(params.idapp, 0, 0, true);
  if (!recfindFondo) {
    let myNave = new Nave({ idapp, ind_order: 0, riga: 0, col: 0 });
    myNave.created = new Date();
    myNave.parent_id = ObjectID("5e592aecbfd0b75f3021d9c9");
    await myNave.save();

    await NavePersistente.addRecordNavePersistenteByParams({ idapp, riga: 0, col: 0, riga1don: 0, col1don: 0 });

    const userFondo = await User.findByIndOrder(idapp, 0);
    if (!userFondo || userFondo === undefined) {
      await telegrambot.sendMsgTelegramToTheAdmin(idapp, 'Devi creare l\'utente FONDO , con ind_order = 0 ! ');
    }
  }

  const arrlistaingresso = await ListaIngresso.getProssimiInLista(idapp, true);

  let index = 0;
  for (const reclista of arrlistaingresso) {

    params.ind_order = reclista.ind_order;
    params.id = reclista._id;
    params.num_tess = reclista.num_tess;

    await Nave.addUserFromListaIngresso_IntoNave(index === 0, idapp, params, false);
    index++;

    if (index >= params.numpersone)
      break;
  }

  return params.conta;

};

async function addUserToNave(idapp, rec) {

  let params = {};

  params.id = rec._id;
  params.num_tess = rec.num_tess;

  return await Nave.addUserFromListaIngresso_IntoNave(true, idapp, params, true);

}

NaveSchema.statics.checkIfDevoAggiungereInNave = async function (idapp) {

  const { ListaIngresso } = require('./listaingresso');

  // Ottieni la lista Ordinata in base al numero d'invitati
  arrlista = await ListaIngresso.getProssimiInLista(idapp, true);

  for (const rec of arrlista) {
    await addUserToNave(idapp, rec);
  }

};

NaveSchema.statics.pulisciNonPresenzeInNave = async function (idapp) {
  const Nave = this;

  let numrec = 0;

  const { ListaIngresso } = require('./listaingresso');

  const myquery = getQueryProj({
    idapp,
    ind_order: { $gt: 0 },
    added: true,
    deleted: false,
  });

  arrrec = await ListaIngresso.aggregate(myquery)
    .then(async (arrlista) => {
      for (const rec of arrlista) {
        const trovato = await Nave.findByIndOrderAndNumTess(idapp, rec.ind_order, rec.num_tess);
        if (!trovato) {
          let fields_to_update = { added: false };
          await ListaIngresso.findOneAndUpdate({ _id: rec._id }, { $set: fields_to_update }, { new: false });
          numrec++;
        }
      }

    });

  return numrec;

};

NaveSchema.statics.visuNaviUtentiEliminati = async function (idapp) {
  const Nave = this;

  let numrec = 0;

  const myquery = getQueryProj({ idapp });

  arrrec = await Nave.aggregate(myquery).sort({ riga: 1, col: 1 });

  let mystr = 'ELIMINATI: \n';
  let conta = 0;
  for (const rec of arrrec) {
    if (!rec.username) {
      let navepersistente = await NavePersistente.findByRigaColByDonatore(idapp, rec.riga, rec.col, 0);
      if (!!navepersistente) {
        mystr += '[' + conta + '] [NAVI ' + navepersistente.riga + '.' + navepersistente.col + '] [' + rec.riga + '.' + rec.col + '] ' + rec.ind_order;
        mystr += ' num_tess = ' + rec.num_tess;
        mystr += '\n';
        conta++;
      }
    }
  }

  return { mystr, num: conta };
};


NaveSchema.statics.getNaveByUser = async function (idapp, username, lang, fuoco) {
  const Nave = this;

  let mystr = '';
  let rec = {};
  try {
    const arrposiz = await Nave.getArrPosizioniByUsername(idapp, username);
    if (!!arrposiz) {
      for (const pos of arrposiz) {
        let mypos = {
          riga: pos.riga,
          col: pos.col,
          numup: 3,
        };
        tools.getRigaColByPosUp(mypos);

        let persistente = await NavePersistente.findByRigaColByDonatore(idapp, pos.riga, pos.col, 0);
        if (!!persistente) {
          if (persistente.provvisoria) {
            mystr += tools.ACAPO + tools.get__('NAVE', lang) + ' ' + '[' + mypos.riga + '.' + mypos.col + '] - ' + tools.get__('TEMPORANEA', lang) + tools.ACAPO + tools.ACAPO;
          } else {
            mystr += await Nave.getNavePos(idapp, mypos.riga, mypos.col, false, ind_order);
          }
        }
        // mystr += await Nave.getPlaccaPerDonatore(idapp, pos.riga, pos.col, false, rec);
        // mystr += await Nave.getPlaccaPerMediatore(idapp, pos.riga, pos.col, false, rec);
      }
    }
  } catch (e) {
    console.error(e.message);
  }

  return mystr;
};

NaveSchema.statics.getNaveByRigaCol = async function (idapp, rigapos, colpos) {
  const Nave = this;

  rec = {};
  rec = await Nave.getPlaccaPerMediatore(idapp, rigapos, colpos, true, rec);

  if (rigapos < 4) {
    rigapos = 4;
    colpos = 1;
  }
  rec = await Nave.getPlaccaPerDonatore(idapp, rigapos, colpos, true, rec);

  return rec;
};

NaveSchema.statics.getDonatoridelSognatore = async function (idapp, riganave, colnave) {
  const Nave = this;

  coldonatoreIni = ((colnave - 1) * 64) + (1);
  coldonatoreFine = coldonatoreIni + (63);

  const myquery = getQueryProj({
    idapp,
    riga: riganave + 6,
    col: { $gte: coldonatoreIni, $lte: coldonatoreFine }
  });

  const arrnaviout = [];

  const arrnavi = await Nave.aggregate(myquery);

  for (const nave of arrnavi) {
    // Se è il mediatore, allora non includerlo nei Donatori!
    mypos = {
      riga: nave.riga,
      col: nave.col,
      numup: 3,
    };

    tools.getRigaColByPosUp(mypos);

    const navemediatore = await Nave.findByRigaCol(idapp, mypos.riga, mypos.col, true);
    if (!!navemediatore) {
      if (navemediatore.ind_order !== nave.ind_order) {
        arrnaviout.push(nave);
      }
    } else {
      arrnaviout.push(nave);
    }
  }

  return arrnaviout;

};

NaveSchema.statics.ricalcolaNave = async function (idapp, nave, riga1don, col1don, ricalcola, index) {
  const Nave = this;

  try {
    if (nave === null) {
      nave = await NavePersistente.findByRigaColByDonatore(idapp, riga1don, col1don, 0);
    }
    nave.rec = await Nave.getNaveByRigaCol(idapp, nave.riga1don, nave.col1don);

    if (nave.provvisoria || (ricalcola && (nave.DoniConfermati === nave.DoniTotali) && (nave.DoniTotali >= 7) && nave.DoniMancanti === 0 && nave.DoniAttesaDiConferma === 0)) {
      // gia fatto

    } else {
      nave.index = index;

      nave.DoniTotali = 0;
      nave.DoniAttesaDiConferma = 0;
      nave.DoniMancanti = 0;
      nave.DoniConfermati = 0;

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

      if (!!nave.tutor)
        nave.tutor_namesurname = await User.getNameSurnameByUsername(idapp, nave.tutor);

      if (!!nave.rec) {
        if (!!nave.rec.donatore) {
          nave.DoniTotali = nave.rec.donatore.arrdonatori.filter((rec) => (!(rec.ind_order === nave.rec.donatore.recmediatore.ind_order && (rec.num_tess % 2) === 0))).reduce((sum, item) => sum + 1, 0);
          nave.DoniAttesaDiConferma = nave.rec.donatore.arrdonatori.filter((rec) => (!!rec.date_made_gift && !rec.made_gift && !(rec.ind_order === nave.rec.donatore.recmediatore.ind_order && (rec.num_tess % 2) === 0))).reduce((sum, item) => sum + 1, 0);
          nave.DoniMancanti = nave.rec.donatore.arrdonatori.filter((rec) => (!rec.made_gift && !(rec.ind_order === nave.rec.donatore.recmediatore.ind_order && (rec.num_tess % 2) === 0))).reduce((sum, item) => sum + 1, 0);
          nave.DoniConfermati = nave.rec.donatore.arrdonatori.filter((rec) => rec.made_gift && !(rec.ind_order === nave.rec.donatore.recmediatore.ind_order && (rec.num_tess % 2) === 0)).reduce((sum, item) => sum + 1, 0);
        }
      }

      const fieldsvalue = {
        DoniAttesaDiConferma: nave.DoniAttesaDiConferma,
        DoniTotali: nave.DoniTotali,
        DoniMancanti: nave.DoniMancanti,
        DoniConfermati: nave.DoniConfermati,
        tutor_namesurname: nave.tutor_namesurname,
      };

      const risu = await NavePersistente.findOneAndUpdate({ _id: nave._id }, { $set: fieldsvalue }, { new: false });

      nave._doc.rec = nave.rec;
    }
  } catch (e) {
    console.error(e.message);
  }

  return nave;

};

NaveSchema.statics.getNextNumTess = async function (idapp, ind_order) {
  const Nave = this;

  const rec = await Nave.findOne({ idapp, ind_order }, { num_tess: 1 }).sort({ num_tess: -1 });
  if (!!rec) {

    if (rec.num_tess % 2 === 0) {
      rec.num_tess++;
    } else {
      rec.num_tess += 2;
    }

    return rec.num_tess
  } else {
    return 1;
  }

};

NaveSchema.statics.getnumNaviByUsername = async function (idapp, username) {
  const Nave = this;

  try {

    const { ListaIngresso } = require('./listaingresso');

    // Get array di ind_order
    const arrind_order = await ListaIngresso.find({ idapp, username }).distinct('ind_order');

    const arrrec = await Nave.find({ idapp, ind_order: arrind_order, num_tess: { $mod: [ 2 , 1] } }, {
      riga: 1,
      col: 1,
      ind_order: 1
    });

    if (!!arrrec)
      return arrrec.length;
    else
      return 0;

  }catch (e) {
    console.error(e.message);
  }
};

NaveSchema.statics.getSognatoreByRigaColMediatore = async function (idapp, navemediatore) {

  const ris = this.getRigaColSognatoreByMediatore(idapp, navemediatore.riga, navemediatore.col, 3);

  const myquery = getQueryProj({
    idapp,
    riga: ris.riga,
    col: ris.col,
  });

  arrrec = await Nave.aggregate(myquery);

  if (!!arrrec) {
    if (arrrec.length > 0)
      return arrrec[0];
  }

  return null;
};



const Nave = mongoose.model('Nave', NaveSchema);

module.exports = { Nave };


