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

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

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

const CartSchema = new Schema({
  idapp: {
    type: String,
  },
  userId: { type: Schema.Types.ObjectId, ref: 'User' },
  totalQty: { type: Number, default: 0 },
  totalPrice: { type: Number, default: 0 },
  totalPriceCalc: { type: Number, default: 0 },
  totalPriceIntero: { type: Number, default: 0 },
  department: {
    type: String,
    ref: 'Department',
  },
  items: [
    {
      order: { type: Schema.Types.ObjectId, ref: 'Order' },
    },
  ],
  note: {
    type: String,
  },
  codice_sconto: {
    type: String,
  },
  descr_sconto: {
    type: String,
  },
  note_ordine_gas: {
    type: String,
  },
  modify_at: {
    type: Date,
  },
});

var Cart = (module.exports = mongoose.model('Cart', CartSchema));

module.exports.findAllIdApp = async function (idapp, userId) {
  const myfind = { idapp, userId };

  return await Cart.findOne(myfind).lean();
};

module.exports.getCartByUserId = async function (uid, idapp) {
  try {
    let mycart = await getCart(uid, idapp);
    if (!mycart) return null;

    await updateOrderDetails(mycart.items);
    let haschanged = await filterValidItems(mycart);
    // haschanged = true;
    if (haschanged) {
      const CartClass = require('../modules/Cart')
      await saveCartItemsOrder(mycart);
      mycart = await CartClass.aggiornaCarrelloByCart(mycart, uid, idapp);
    }

    return mycart;
  } catch (e) {
    console.log('getCartByUserId err', e);
  }
};

module.exports.getCartCompletoByCartId = async function (id_cart, idapp) {
  try {
    const mycart = await getCartById(id_cart, idapp);
    if (!mycart) return null;

    await updateOrderDetails(mycart.items);
    await filterValidItems(mycart);

    return mycart;
  } catch (e) {
    console.log('getCartByUserId err', e);
  }
};

// Recupera il carrello per l'utente e l'app
async function getCart(uid, idapp) {
  const query = { userId: uid, idapp };
  return await Cart.findOne(query).lean();
}

async function saveCartItemsOrder(cart) {
  // aggiorna solo gli'id dell'order in items
  for (const item of cart.items) {
    item.order = item.order._id;
  }

  return await Cart.updateOne({ _id: cart._id }, { $set: { items: cart.items } });
}

async function getCartById(id_cart, idapp) {
  return await Cart.findOne({ _id: id_cart }).lean();
}

// Aggiorna i dettagli dell'ordine per ogni articolo nel carrello
async function updateOrderDetails(items) {
  const Order = require('../models/order');

  for (const item of items) {
    try {
      const idorder = item.order ? item.order._id.toString() : item._id.toString();
      const myord = await Order.getTotalOrderById(idorder);

      if (myord.length > 0) {
        item.order = myord[0];
      }
    } catch (e) {
      console.log('err', e);
    }
  }
}

async function checkIfExistProduct(code) {
  const Product = require('../models/product');
  try {
    const prod = await Product.findOne({ 'productInfo.code': code }).exec();
    if (prod && prod.active) {
      return prod;
    } else {
      return null;
    }
  } catch (e) {
    console.log('err', e);
    return null;
  }
}

// Filtra solo gli articoli validi (con quantità > 0 o pre-ordinati)
async function filterValidItems(mycart) {
  try {
    mycart.newitems = [];
    let haschanged = false;

    for (let item of mycart.items) {
      try {
        if (
          item.order &&
          item.order.hasOwnProperty('idapp') &&
          item.order.product.productInfo &&
          (item.order.quantity > 0 || item.order.quantitypreordered > 0) &&
          (await checkIfExistProduct(item.order.product.productInfo.code))
        ) {
          mycart.newitems.push(item);
        } else {
          const Order = require('./order');
          const OrdersCart = require('./orderscart');

          // Cancella l'ordine su Order e OrderCart e cancella il record su Cart
          if (item.order) {
            await OrdersCart.deleteOrderById(item.order._id.toString());
            await Order.deleteOrderById(item.order._id.toString());
          }

          haschanged = true;
        }
      } catch (e) {
        console.log('err', e);
      }
    }
    mycart.items = [...mycart.newitems];
    mycart.newitems = [];
    return haschanged;
  } catch (e) {
    console.log('err', e);
    return false;
  }
}

module.exports.updateCartByUserId = async function (userId, newCart) {
  const query = { userId: userId };

  try {
    // Cerca il carrello esistente nel database
    const existingCart = await Cart.findOne(query);

    if (existingCart) {
      // Se il carrello esiste, aggiorna i dati
      const updatedCart = await Cart.findOneAndUpdate(
        query,
        {
          $set: {
            items: newCart.items,
            totalQty: newCart.totalQty,
            totalPrice: newCart.totalPrice,
            totalPriceIntero: newCart.totalPriceIntero,
            totalPriceCalc: newCart.totalPriceCalc,
            userId: userId,
          },
        },
        { new: true } // Restituisce il documento aggiornato
      );

      return updatedCart; // Restituisce il carrello aggiornato
    } else {
      // Se il carrello non esiste, crea un nuovo documento
      const createdCart = new Cart(newCart);
      await createdCart.init();
      const savedCart = await createdCart.save();
      return savedCart; // Restituisce il carrello creato
    }
  } catch (err) {
    // Gestione degli errori
    console.error("Errore durante l'aggiornamento del carrello:", err);
    throw err; // Propaga l'errore al chiamante
  }
};

module.exports.updateCartByCartId = async function (cartId, newCart) {
  // delete newCart._doc._id;
  const items = newCart.items;
  const totalQty = newCart.totalQty;
  const totalPrice = newCart.totalPrice;
  const totalPriceCalc = newCart.totalPriceCalc;
  const totalPriceIntero = newCart.totalPriceIntero;
  const note = newCart.note;
  const codice_sconto = newCart.codice_sconto;
  const descr_sconto = newCart.descr_sconto;
  const note_ordine_gas = newCart.note_ordine_gas;

  const modify_at = new Date();

  return await Cart.findOneAndUpdate(
    { _id: cartId },
    {
      $set: {
        items,
        totalPrice,
        totalPriceCalc,
        totalPriceIntero,
        totalQty,
        note,
        codice_sconto,
        descr_sconto,
        note_ordine_gas,
        modify_at: new Date(),
      },
    },
    { new: false }
  )
    .lean()
    .then((ris) => {
      return ris;
    })
    .catch((err) => {
      console.log('err', err);
      return null;
    });
};

module.exports.deleteCartByCartId = async function (cartId) {
  return await Cart.deleteOne({ _id: cartId });
};

module.exports.createCart = async function (newCart) {
  return await newCart.save();
};

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