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

const escapeStringRegexp = require('escape-string-regexp');

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

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

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

const fs = require('fs-extra');

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

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

const CitySchema = new Schema({
  _id: {
    type: Number,
  },
  istat: {
    type: String,
  },
  comune: {
    type: String,
  },
  prov: {
    type: String,
    maxlength: 3,
  },
  reg: {
    type: String,
    maxlength: 3,
  },
  pref: {
    type: String,
  },
  cap: {
    type: String,
    maxlength: 6,
  },
  abitanti: {
    type: String,
  },
  country: {
    type: String,
    maxlength: 3,
  },
  geojson: {
    type: Object, // Tipo che può contenere le features GeoJSON
  },
});

CitySchema.pre('save', async function (next) {
  if (this.isNew) {
    const myrec = await City.findOne().limit(1).sort({ _id: -1 });
    if (!!myrec) {
      if (myrec._doc._id === 0)
        this._id = 1;
      else
        this._id = myrec._doc._id + 1;

    } else {
      this._id = 1;
    }
  }

  next();
});

CitySchema.statics.getProvinceByIdCity = async function (idcity) {
  const myrec = await City.findOne({ _id: idcity }).lean();
  if (myrec) {
    return myrec.prov;
  }

  return '';
}
CitySchema.statics.getRecCityByIdCity = async function (idcity) {
  const myrec = await City.findOne({ _id: idcity }).lean();
  return myrec;
}

CitySchema.statics.getCircuitNameBystrProv = async function (strProv) {
  const { Circuit } = require('../models/circuit');

  const myrec = await Circuit.findOne({ strProv }).lean();
  if (myrec) {
    return myrec.name;
  }

  return '';
}

CitySchema.statics.getRegionByIdCity = async function (idcity) {
  const myrec = await City.findOne({ _id: idcity }).lean();
  if (myrec) {
    return myrec.reg;
  }

  return '';
}

CitySchema.statics.findByCity = function (mycity) {

  let myregexp = new RegExp(mycity.trim().replace(' ', '|'), 'ig');

  const query = [
    { $match: { comune: { $regex: myregexp } } },
    { $sort: { descr: 1 } },
  ];

  return City.aggregate(query).then((arrrec) => {
    return arrrec;
  });

};

CitySchema.statics.getFieldsForSearch = function () {
  return [
    { field: 'comune', type: tools.FieldType.string },
    { field: 'prov', type: tools.FieldType.string },
    { field: 'reg', type: tools.FieldType.string },
    { field: 'pref', type: tools.FieldType.number },
    { field: 'cap', type: tools.FieldType.number },
  ];
};

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

  const strfind = params.search;

  if (strfind === '') {
    return [];
  }

  return tools.executeQueryTable(this, 0, params);
};

CitySchema.statics.executeQueryPickup = async function (idapp, params) {

  const strfind = params.search;

  if (strfind === '' && !params.filter) {
    return [];
  }

  let filterfindexact = {};
  if (strfind) {
    filterfindexact = { comune: strfind };
  }

  let limit = 10;
  let risexact = [];

  let filterfind = { comune: { $regex: '^' + strfind, $options: 'i' } };

  let aggr1 = [
    {
      $match: { comune: strfind },
    },
    { $limit: 1 },
    {
      $project: {
        comune: { $concat: ["$comune", " (", "$prov", ")"] },
        comune_solo: { $concat: ["$comune", ""] },
        prov: 1,
      },
    },
  ];

  if (params.filter) {
    filterfind = { ...params.filter, ...filterfind };
    limit = 200;
  } else {
    // risexact = await City.find(filterfindexact, {comune: 1, prov: 1, reg: 1}).lean();
    risexact = await City.aggregate(aggr1);
  }

  let aggr2 = [
    {
      $match: filterfind,
    },
    { $limit: limit },
    {
      $project: {
        comune: { $concat: ["$comune", " (", "$prov", ")"] },
        comune_solo: { $concat: ["$comune", ""] },
        prov: 1,
      },
    },
  ];


  // let ris = await City.find(filterfind, {comune: 1, prov: 1, reg: 1}).lean().limit(limit);
  let ris = await City.aggregate(aggr2).limit(limit);

  return [...risexact, ...ris];

};

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

  return await City.find(myfind).lean();
};

CitySchema.statics.getGeoJsonByProvince = async function (prov) {
  let ris = null;
  if (prov)
    ris = await City.find({ prov }).lean();
  else
    ris = await City.find({}).lean();

  try {
    if (ris) {
      const arrjson = ris
        .filter(record => record.geojson && typeof record.geojson === 'object' && record.geojson.geometry) // Prima filtra per mantenere solo gli oggetti con "geometry"
        .map((record, index) => {
          // Crea un nuovo oggetto con gli attributi desiderati da ogni record
          const newRecord = {
            ...record.geojson, // Spread dell'oggetto geojson per prendere tutte le sue proprietà
            id: (index + 1).toString(), // Aggiunge un valore "id" incrementale in base all'indice
          };

          // Aggiungi o aggiorna la proprietà "prov" in "properties" dentro l'oggetto geojson
          if (newRecord.properties) {
            newRecord.properties.prov = record.prov; // Se "properties" esiste già
          } else {
            newRecord.properties = { prov: record.prov }; // Crea "properties" se non esiste
          }

          return newRecord;
        });

      return arrjson;
    }
    return [];
  } catch (e) {
    console.error('Err', e);
  }

  return null
};


CitySchema.statics.insertGeojsonToMongoDB = async function (nomefilejson) {
  try {
    // Lettura del file GeoJSON
    const geojson = await fs.readJson(nomefilejson); // Sostituisci con il percorso del tuo file GeoJSON

    let inseriti = 0;
    const numcomuni = geojson.features.length;
    for (const citta of geojson.features) {

      // Identifica il documento esistente in cui vuoi aggiungere le features
      const reccity = await City.findOne({ istat: String(citta.properties.ISTAT).padStart(6, '0') });

      if (reccity) {
        const ris = await City.updateOne({ _id: reccity._id }, { $set: { geojson: citta } });
        if (ris.acknowledged) {
          inseriti++;
        }
      }

    }

    console.log(`${inseriti} su ${numcomuni} comuni inseriti.`);
  } catch (e) {
    console.error('Err', e);
  }

};



const City = mongoose.model('City', CitySchema);

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


module.exports = { City };
