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

const tools = require('../tools/general');
const { ObjectId } = require('mongodb');

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

const { MySchedaSchema, IDimensioni, IImg, IText, IAreaDiStampa } = require('../models/myscheda');

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

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

const IElementiPagina = new Schema({
  isTemplate: Boolean,
  linkIdTemplate: String,
  name: String,
  pagina: IDimensioni,
});

const myCard = new Schema({
  imagefile: String,
  vers_img: Number,
  alt: String,
  description: String,
  style: String,
  size: String,
  color: String,
  content: String,
  colorsub: String,
  link: String,
});
const animation = new Schema({
  name: String,
  clduration: String,
  cldelay: String,
  timingtype: String,
});

const elemText = new Schema({
  text: String,
  color: String,
  class: String,
  size: String,
  anim: animation,
});

const catalogo = new Schema({
  //++AddCATALOGO_FIELDS
  idCatalogSel: { type: String },
  productTypes: [{ type: Number }],
  excludeproductTypes: [{ type: Number }],
  editore: [{ type: String }],
  argomenti: [{ type: String }],
  idCollane: [{ type: String }],
  idTipologia: [{ type: Number }],
  idTipoFormato: [{ type: Number }],
  sort_field: { type: String },
  sort_dir: { type: Number },
  pdf: { type: Boolean },
  pdf_filename: { type: String },
  printable: { type: Boolean },
  indebug: { type: Boolean },
  maxnumlibri: { type: Number },
  showListaArgomenti: { type: Boolean },
  showOnlyCatalogoPDF: { type: Boolean },
  showListaCollane: { type: Boolean },

  first_page: IDimensioni,
  last_page: IDimensioni,
  areadistampa: IAreaDiStampa,

  print_isTemplate: Boolean,
  print_linkIdTemplate: String,

  dimensioni_def: IElementiPagina,

  // -------------------
  arrSchede: [
    {
      scheda: MySchedaSchema,
      order: { type: Number },
      numPagineMax: { type: Number },
      /*arrProdToShow: {
          type: [[mongoose.Schema.Types.Mixed]], // Definizione tipo
          select: false // Imposta il campo come non selezionabile
        },*/
    },
  ],
});

const MySingleElemSchema = {
  idapp: {
    type: String,
  },
  path: {
    type: String,
  },
  /*oldpath: {
    type: String,
  },*/
  idElemParent: {
    type: String,
  },
  idPage: { type: String },
  type: {
    type: Number,
  },
  img: {
    type: String,
  },
  container: {
    type: String,
  },
  container2: {
    type: String,
  },
  container3: {
    type: String,
  },
  container4: {
    type: String,
  },
  align: {
    type: Number,
  },
  vertalign: {
    type: Number,
  },
  speed: {
    type: Number,
  },
  parambool: {
    type: Boolean,
  },
  span: {
    type: Boolean,
  },
  parambool2: {
    type: Boolean,
  },
  parambool3: {
    type: Boolean,
  },
  parambool4: {
    type: Boolean,
  },
  parambool5: {
    type: Boolean,
  },
  number: {
    type: Number,
  },
  num2: {
    type: Number,
  },
  imgback: {
    type: String,
  },
  ratio: {
    type: String,
  },
  containerHtml: {
    type: String,
  },
  size: {
    type: String,
  },
  order: {
    type: Number,
    default: 0,
  },
  height: {
    type: Number,
  },
  heightimg: {
    type: String,
  },
  heightcarousel: {
    type: String,
  },
  widthimg: {
    type: String,
  },
  width: {
    type: Number,
  },
  heightcard: {
    type: String,
  },
  widthcard: {
    type: String,
  },
  link: {
    type: String,
  },
  fit: {
    type: String,
  },
  onlyif_logged: {
    type: Boolean,
  },
  color: {
    type: String,
  },
  elemsText: [elemText],
  anim: animation,
  features: [
    {
      name: {
        type: String,
      },
      icon: {
        type: String,
      },
      description: {
        type: String,
      },
    },
  ],
  active: {
    type: Boolean,
    default: false,
  },
  class: {
    type: String,
  },
  class2: {
    type: String,
  },
  class3: {
    type: String,
  },
  class4: {
    type: String,
  },
  stiletit_str: {
    type: String,
  },
  stiletit_icon: {
    type: String,
  },
  styleadd: {
    type: String,
  },
  image: {
    type: String,
  },
  vers_img: {
    type: Number,
  },
  titleBanner: String,
  classBanner: String,
  listcards: [myCard],
  catalogo: catalogo,
  list: [
    {
      imagefile: {
        type: String,
      },
      vers_img: {
        type: Number,
      },
      order: {
        type: Number,
      },
      alt: {
        type: String,
      },
      description: {
        type: String,
      },
    },
  ],
  date_created: {
    type: Date,
    default: Date.now,
  },
  date_updated: {
    type: Date,
  },
};

const MyElemSchema = new Schema({
  ...MySingleElemSchema,
  // Aggiungi rows e columns
  rows: {
    type: [
      {
        ...MySingleElemSchema,
        columns: {
          type: [
            {
              ...MySingleElemSchema,
              elems: [MySingleElemSchema],
            },
          ],
        },
      },
    ],
  },
});

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

  next();
});

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

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

MyElemSchema.statics.SetIdPageInsteadThePah = async function (idapp) {
  const MyElem = this;
  const { MyPage } = require('../models/mypage');

  try {
    const pages = await MyPage.find({ idapp });

    if (pages.length === 0) {
      return 'Nessuna pagina trovata per questo idapp.';
    }

    const bulkOps = [];

    pages.forEach((page) => {
      if (page.path) {
        // Aggiorna documenti con 'path'
        bulkOps.push({
          updateMany: {
            filter: { idapp: idapp, path: page.path },
            update: {
              $set: { idPage: page._id, oldpath: page.path },
              $unset: { path: '' },
            },
          },
        });

        // Aggiorna documenti con 'oldpath' ma senza 'idPage'
        bulkOps.push({
          updateMany: {
            filter: {
              idapp: idapp,
              oldpath: page.path,
              idPage: { $exists: false },
            },
            update: { $set: { idPage: page._id } },
          },
        });
      }
    });

    if (bulkOps.length > 0) {
      const result = await MyElem.bulkWrite(bulkOps);
      console.log(`Aggiornati ${result.modifiedCount} documenti.`);
      return `Aggiornamenti effettuati: ${result.modifiedCount} documenti.`;
    }

    return 'Nessun documento da aggiornare.';
  } catch (error) {
    console.error("Errore durante l'aggiornamento:", error);
    throw error;
  }
};

MyElemSchema.statics.deleteAllFromThisPage = async function (id) {
  const MyElem = this;

  return MyElem.deleteMany({ idPage: id });
};
MyElemSchema.statics.findAllIdApp = async function (idapp) {
  const MyElem = this;

  const myfind = { idapp };

  const aggiorna = false;

  let arrrec = null;

  if (aggiorna) {
    arrrec = await MyElem.find(myfind).sort({ order: 1 });
    for (const elem of arrrec) {
      if (elem.heightimg === 'NaNpx') {
        elem.heightimg = '';
        await elem.save();
      }
    }
  } else {
    arrrec = await MyElem.find(myfind).lean().sort({ order: 1 });
  }

  return arrrec;
};

async function deleteOldMyElems(idapp) {
  try {
    const { MyPage } = require('../models/mypage');

    // 1. Recupera tutti gli _id dalle pagine
    const existingPages = await MyPage.find({ idapp }).select('_id').lean();
    const existingPageIds = existingPages.map((page) => page._id.toString());

    // 2. Trova gli MyElem che hanno idPage non esistenti in MyPage
    const elemsToDelete = await MyElem.find({
      idapp,
      idPage: { $nin: existingPageIds },
    });

    if (elemsToDelete.length > 0) {
      // 3. Esegui la cancellazione
      const result = await MyElem.deleteMany({ idPage: { $nin: existingPageIds } });
      console.log(`Cancellati ${result.deletedCount} documenti di MyElem.`);
    } else {
      console.log('Nessun documento da cancellare.');
    }
  } catch (error) {
    console.error('Errore durante la cancellazione dei documenti:', error);
  }
}

/**
 * Trova tutte le schede template associate a pagine di idapp.
 * Restituisce un array di ogge tti con le seguenti proprietà:
 * - scheda: l'oggetto scheda, con proprietà come _id, name, isTemplate
 * - idPageOrig: l'idPage originale associata alla scheda
 *
 * Se idapp === '18', stampa i duplicati e i titoli delle pagine
 * e cancella i documenti di MyElem con idPage non esistenti in MyPage
 *
 * @param {string} idapp ID dell'applicazione
 * @returns {Promise<IMyElemTemplate[]>} Array di oggetti scheda con idPageOrig
 */
MyElemSchema.statics.findallSchedeTemplate = async function (idapp) {
  const MyElem = this;

  try {
    const { MyPage } = require('../models/mypage');

    const ris = await MyElem.find({ idapp }).lean();

    const schedeTemplate = ris.flatMap((elem) =>
      elem.catalogo && elem.catalogo.arrSchede
        ? elem.catalogo.arrSchede
            .filter((scheda) => scheda.scheda?.isTemplate)
            .map((scheda) => ({
              ...scheda, // mantieni i dati originali della scheda
              idPageOrig: elem.idPage, // aggiungi l'idPage
            }))
        : []
    );

    if (idapp === '18') {
      const duplicateIds = schedeTemplate.reduce((acc, scheda) => {
        const id = scheda.scheda._id; // Ottieni l'ID della scheda
        if (!acc[id]) {
          acc[id] = []; // Inizializza un array per tenere traccia delle pagine
        }
        acc[id].push(scheda.idPageOrig); // Aggiungi l'idPage all'array
        return acc;
      }, {});

      // Filtra i duplicati
      const duplicates = Object.entries(duplicateIds)
        .filter(([_, pages]) => pages.length > 1) // Mantieni solo gli ID con più di un'istanza
        .map(([id, pages]) => ({ id, pages })); // Ottieni ID e pagine corrispondenti

      // Recupera i dettagli delle pagine
      const pageIds = duplicates.flatMap((dup) => dup.pages); // Estrai tutti gli idPage
      const pages = await MyPage.find({ idapp, _id: { $in: pageIds } }).lean();

      // Crea una mappatura tra idPage e title
      const pageMap = pages.reduce((acc, page) => {
        acc[page._id] = page.title; // Mappa idPage a title
        return acc;
      }, {});

      // Associa i titoli delle pagine agli ID duplicati
      const resultWithTitles = duplicates.map((dup) => ({
        id: dup.id,
        pages: dup.pages.map((_id) => ({
          _id,
          title: pageMap[_id] || 'Titolo non trovato', // Usa la mappatura per trovare il titolo
        })),
      }));

      if (resultWithTitles.length > 0) {
        console.log('Duplicati e titoli delle pagine:', JSON.stringify(resultWithTitles, null, 2));
        // await deleteOldMyElems(idapp);
      }
    }

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

/**
 * Ricerca tra tutte le schede, contenute in catalogo, se esiste un nome di template uguale,
 * se non lo trova allora è quello giusto per crearne uno nuovo
 *
 * @param {string} idapp - ID dell'app
 * @param {string} idPageOrig - ID della pagina originale
 * @param {string} nomeTemplate - Nome del template
 *
 * @returns {string} Il nome del template libero
 */
MyElemSchema.statics.getNewFreeNameTemplate = async function (idapp, idPageOrig, nomeTemplate) {
  const MyElem = this;

  try {
    // Trova tutti gli elementi che hanno un template con lo stesso nome
    const ris = await MyElem.find(
      {
        idapp,
        'catalogo.arrSchede.scheda.isTemplate': true,
        'catalogo.arrSchede.scheda.idPage': { $ne: idPageOrig },
      },
      {
        'catalogo.arrSchede.scheda.name': 1,
        'catalogo.arrSchede.scheda.isTemplate': 1,
        'catalogo.arrSchede.scheda.isPagIntro': 1,
        'catalogo.arrSchede.scheda.idPage': 1,
      }
    );

    // Recupera i nomi dei template già esistenti
    const existingNames = new Set(
      ris.flatMap(
        (elem) =>
          elem.catalogo?.arrSchede
            ?.filter((scheda) => scheda.scheda?.isTemplate && scheda.scheda?.idPage !== idPageOrig)
            .map((scheda) => scheda.scheda?.name) || []
      )
    );

    // Crea un nuovo nome di template univoco
    let ind = 2;
    let newNameTemplate;

    do {
      newNameTemplate = `${nomeTemplate}_copia_${ind}`;
      ind++;
    } while (existingNames.has(newNameTemplate) && ind <= 1000);

    return newNameTemplate;
  } catch (e) {
    console.error('Err', e);
    throw e; // Propagate the error
  }
};

MyElemSchema.statics.findParentElem = async function (idapp, idElemParent) {
  try {
    let myelemParent = null;

    myelemParent = await this.findOne({
      idapp,
      rows: {
        $elemMatch: { columns: { $elemMatch: { _id: idElemParent } } },
      },
    }).lean();

    return myelemParent;
  } catch (e) {
    console.error('Err', e);
    throw e; // Propagate the error
  }
};

const MyElem = mongoose.model('MyElem', MyElemSchema);

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

module.exports = { MyElem };
