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

const express = require('express');
const router = express.Router();

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

var server_constants = require('../tools/server_constants');

var { Project } = require('../models/project');

const Scontistica = require('../models/scontistica');

var { authenticate, auth_default } = require('../middleware/authenticate');

const _ = require('lodash');

const Product = require('../models/product');
const Order = require('../models/order');
const Variant = require('../models/variant');
const { User } = require('../models/user');

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

/*const Department = require('../models/Department')
const Category = require('../models/Category')
const TypedError = require('../modules/ErrorHandler')
const paypal_config = require('../configs/paypal-config')
const paypal = require('paypal-rest-sdk')
 */

const CartClass = require('../modules/Cart');
const Cart = require('../models/cart');
const OrdersCart = require('../models/orderscart');

//GET cart
router.get('/:userId', authenticate, async function (req, res, next) {
  try {
    let userId = req.params.userId;
    let idapp = req.user.idapp;

    const cart = await Cart.getCartByUserId(userId, idapp);
    if (cart) return res.send({ code: server_constants.RIS_CODE_OK, cart });
    else return res.send({ code: server_constants.RIS_CODE_OK, cart: null });
  } catch (err) {
    console.error('Err', err);
    return res.send({ code: server_constants.RIS_CODE_ERR, cart: null });
  }
});

async function aggiornaCarrello(mycartpar, userId, idapp) {
  try {
    let mycart = mycartpar;

    if (!mycart) mycart = await Cart.getCartByUserId(userId, idapp);

    if (!mycart) return null;

    mycart = await Cart.getCartCompletoByCartId(mycart._id, idapp);

    let newCart = await CartClass.constructByCart(mycart);
    if (newCart) return newCart.aggiornaCarrello();

    return newCart;
  } catch (e) {
    console.error('Err AggiornaCarrello', e);
    return null;
  }
}

//POST cart
router.post('/:userId', authenticate, async function (req, res, next) {
  try {
    let idapp = req.body.idapp;
    let userId = req.params.userId;
    let addqty = req.body.addqty;
    let subqty = req.body.subqty;
    let order = req.body.order;

    let mycart = await Cart.getCartByUserId(userId, idapp);

    if (!order) {
      return res.send({ code: server_constants.RIS_CODE_OK, cart: null });
    }

    let codice_sconto = mycart?.codice_sconto;

    // const myorder = Order.getOrderByID(order._id);
    if (!addqty && !subqty && order) {
      order._id = await Order.createOrder(order, codice_sconto);
      if (!order._id) {
        return res.send({ code: server_constants.RIS_CODE_ERR, cart: 0 });
      }
    }

    let cart = null;
    let product = null;
    // no cart save empty cart to database then return response
    let nuovo = false;
    if (!mycart) {
      let oldCart = new CartClass(order);
      cart = await Cart.createCart(oldCart.generateModel());

      mycart = await Cart.getCartByUserId(userId, idapp);
      nuovo = true;
    }

    let newCart = await CartClass.constructByCart(mycart);
    // order = await Product.updateProductInOrder(order);
    if (!nuovo) {
      // Controlla se sto inserendo un prodotto con 2 Negozi, non permetterlo !
      if (newCart.isSameStorehouse(order)) {
        if (addqty) {
          myord = await newCart.addqty(order);
        } else if (subqty) {
          myord = await newCart.subqty(order);
        } else {
          const ind = await newCart.addItem(order);
          const arrord = await Order.getTotalOrderById(order._id);
          myord = arrord ? arrord[0] : null;
        }
      } else {
        return res.send({
          code: server_constants.RIS_CODE_ERR,
          cart: null,
          myord: null,
          msgerr: 'Non è possibile acquistare nello stesso ordine, su negozi differenti!',
        });
      }
    } else {
      await newCart.updatecarttotals(true);
      await newCart.updateExtraOrder();
      const arrord = await Order.getTotalOrderById(order._id);
      myord = arrord ? arrord[0] : null;
    }
    cart = await Cart.updateCartByCartId(mycart._id, newCart.generateModel());

    if (cart) {
      const carttot = await Cart.getCartByUserId(userId, idapp);
      if (order.idProduct) product = await Product.getProductById(order.idProduct);
      else if (order.product) product = await Product.getProductById(order.product._id);
      return res.send({ code: server_constants.RIS_CODE_OK, cart: carttot, myord, product });
    } else {
      console.error('Err:', err);
      return res.send({ code: server_constants.RIS_CODE_ERR, cart: null, myord: null });
    }
  } catch (e) {
    console.error('Err:', e);
    return res.send({ code: server_constants.RIS_CODE_ERR, cart: 0 });
  }
});

router.delete('/:userId', authenticate, async function (req, res) {
  console.log('DELETE Item');
  let idapp = req.query.idapp;
  let userId = req.params.userId;
  let orderId = req.query.orderId;

  const mycart = await Cart.getCartByUserId(userId, idapp);

  const ord = await Order.findOne({ _id: orderId });
  let idProduct = '';
  let product = null;
  if (ord) idProduct = ord.idProduct;

  // Rimuovere l'Ordine
  const recremoved = await Order.deleteOne({ _id: orderId });
  if (recremoved) {
    // Rimuovere l'id sul Carrello

    let newCart = await CartClass.constructByCart(mycart);
    await newCart.removeItem(orderId);
    let carttot = null;
    const cart = await Cart.updateCartByCartId(mycart._id, newCart.generateModel());

    carttot = await Cart.getCartByUserId(userId, idapp);

    if (idProduct) {
      product = await Product.getProductById(idProduct);
    }

    console.log('carttot', carttot);
    return res.send({ code: server_constants.RIS_CODE_OK, cart: carttot, product });
  }

  return res.send({ code: server_constants.RIS_CODE_ERR, cart: null });
});

//PUT cart
router.put('/:userId', authenticate, async function (req, res, next) {
  let userId = req.params.userId;
  let requestProduct = req.body;
  let { productId, color, size } = requestProduct.product;

  try {
    try {
      const cart = await Cart.getCartByUserId(userId);

      try {
        const myprod = await Product.getProductByID(productId);

        let newCart = oldCart.add(myprod, productId, { color, size });

        //exist cart in databse
        if (cart.length > 0) {
          try {
            const result = await Cart.updateCartByUserId(userId, {
              items: newCart.items,
              totalQty: newCart.totalQty,
              totalPrice: newCart.totalPrice,
              totalPriceCalc: newCart.totalPriceCalc,
              totalPriceIntero: newCart.totalPriceIntero,
              userId: userId,
            });
            res.json(result);
          } catch (err) {
            return next(err);
          }
        } else {
          //no cart in database
          let newCartobj = {
            items: newCart.items,
            totalQty: newCart.totalQty,
            totalPrice: newCart.totalPrice,
            totalPriceCalc: newCart.totalPriceCalc,
            totalPriceIntero: newCart.totalPriceIntero,
            userId: userId,
          };
          try {
            const resultCart = await Cart.createCart(newCartobj);
          } catch (err) {
            return next(err);
          }
          res.status(201).json(resultCart);
        }
      } catch (err) {
        return next(err);
      }

      const product = await Product.getProductById(productId);

      return res.send({ code: server_constants.RIS_CODE_OK, product });
    } catch (err) {
      return next(err);
    }

    let oldCart = new CartClass(c || {});
  } catch (e) {
    return res.send({ code: server_constants.RIS_CODE_ERR, status: 0 });
  }
});

router.post('/:userId/app_sc', authenticate, async function (req, res, next) {
  let idapp = req.body.idapp;
  let cart_id = req.body.cart_id;
  let userId = req.params.userId;

  let codice_sconto = req.body.code;
  let options = req.body.options;

  let mycart = null;
  let valido = false;
  let errmsg = '';
  let recscontisticaTrovata = null;

  try {
    let mycart = await Cart.getCartCompletoByCartId(cart_id, idapp);
    // let mycart = await Cart.findOne({ _id: cart_id }).lean();

    if (codice_sconto === 'RIMUOVI') {
      mycart = await Cart.findOneAndUpdate({ _id: cart_id }, { $set: { codice_sconto: '' } }, { new: true }).lean();
      mycart = await aggiornaCarrello(mycart, userId, idapp);
      return res.send({ mycart, valido, msg: 'Codice Sconto rimosso', rimuovi: true });
    }

    // attendi 3 secondi prima di poter inviare una nuova richiesta
    await tools.attendiNSecondi(1);

    if (codice_sconto) {
      const recscontisticheTrovate = await CartClass.getRecSconto(idapp, codice_sconto, true);
      if (recscontisticheTrovate && recscontisticheTrovate.length > 0) {
        recscontisticaTrovata = recscontisticheTrovate[0];
      }

      if (recscontisticaTrovata) {
        if (mycart.codice_sconto !== codice_sconto) {
          mycart.codice_sconto = codice_sconto;
          mycart.descr_sconto = recscontisticaTrovata.description;
          await Cart.updateOne({ _id: cart_id }, { $set: { codice_sconto, descr_sconto: mycart.descr_sconto } });
        }
        valido = true;

        mycart = await aggiornaCarrello(mycart, userId, idapp);
      } else {
        errmsg = `Codice sconto "${codice_sconto}" non valido oppure scaduto`;
      }
    }

    return res.send({ mycart, valido, errmsg, recsconto: recscontisticaTrovata });
  } catch (e) {
    console.error('Err Applica Sconto', e);
    return res.send({ valido: false, mycart: null, errmsg: e.message });
  }
});

// Recupera il carrello
async function getCartById(cart_id) {
  const cart = await Cart.findOne({ _id: cart_id }).lean();
  return cart;
}

// Crea o aggiorna un ordine partendo dal cart
async function createOrUpdateOrderFromCart({ idapp, cart, userId, status, note }) {
  let numorder = await OrdersCart.getLastNumOrder(idapp);
  let numord_pers = await OrdersCart.getLastNumOrdPers(userId, idapp);

  let myorderCart = await OrdersCart.getRecCartByUserId(userId, idapp, numorder);
  if (!myorderCart) {
    numorder++;
    numord_pers++;
    myorderCart = new OrdersCart({
      idapp,
      items: cart.items,
      totalQty: cart.totalQty,
      totalPrice: cart.totalPrice,
      totalPriceCalc: cart.totalPriceCalc,
      totalPriceIntero: cart.totalPriceIntero,
      note_ordine_gas: cart.note_ordine_gas,
      userId,
      status,
      note,
      codice_sconto: cart.codice_sconto,
      descr_sconto: cart.descr_sconto,
      numorder,
      numord_pers,
      created_at: new Date(),
      modify_at: new Date(),
    });
  }

  return myorderCart;
}

// Gestisce l'invio ordine (checkout)
async function handleCheckout({ myorderCart, mycart, userId, idapp, req, options, userDest }) {
  try {
    const ris = await OrdersCart.updateOrdersCartById(-1, myorderCart);
    await Order.updateStatusOrders(mycart.items, shared_consts.OrderStatus.CHECKOUT_SENT);

    await Cart.deleteCartByCartId(mycart._id);

    const orders = await OrdersCart.getOrdersCartByUserId(userId, idapp, myorderCart.numorder);
    if (orders?.[0]) {
      await OrdersCart.updateCmd(orders[0], shared_consts.OrderStatus.CHECKOUT_SENT, true, req, options);
      await sendemail.sendEmail_OrderProduct(userDest.lang, idapp, orders[0], userDest);

      const updatedOrder = await OrdersCart.findById(myorderCart._id).lean();
      return { status: ris.status, orders, recOrderCart: updatedOrder };
    }
  } catch (err) {
    console.error('Errore durante il checkout:', err);
    throw err;
  }
}

//POST cart
router.post('/:userId/createorderscart', authenticate, async function (req, res) {
  try {
    const { idapp, cart_id, status, note, options } = req.body;
    const userId = req.params.userId;

    // console.log('createorderscart', cart_id);

    const mycart = await getCartById(cart_id);
    if (!mycart) {
      return res.send({
        code: server_constants.RIS_CODE_OK,
        status: 0,
        recOrderCart: null,
      });
    }

    let myorderCart = await createOrUpdateOrderFromCart({ idapp, cart: mycart, userId, status, note });
    let statusOrderCart = myorderCart.status;

    const userDest = await User.findById(userId).lean();

    if (status === shared_consts.OrderStatus.CHECKOUT_SENT) {
      try {
        const checkoutResult = await handleCheckout({
          myorderCart,
          mycart,
          userId,
          idapp,
          req,
          options,
          userDest,
        });

        return res.send({
          code: server_constants.RIS_CODE_OK,
          status: checkoutResult.status,
          orders: checkoutResult.orders,
          recOrderCart: checkoutResult.recOrderCart,
        });
      } catch (err) {
        return res.send({ code: server_constants.RIS_CODE_ERR, status: 0 });
      }
    }

    // console.log('SEND OK', statusOrderCart);

    return res.send({
      code: server_constants.RIS_CODE_OK,
      status: statusOrderCart,
      recOrderCart: myorderCart,
    });
  } catch (e) {
    console.error('Errore generale:', e);
    return res.send({ code: server_constants.RIS_CODE_ERR, status: 0, recOrderCart: null });
  }
});

//POST cart
router.post('/:userId/ordercartstatus', authenticate, async function (req, res, next) {
  let idapp = req.body.idapp;
  let userId = req.params.userId;
  let order_id = req.body.order_id;
  let status = req.body.status;
  let options = req.body.options;

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

  let myOrdersCart = await OrdersCart.findOne({ idapp, _id: order_id }).lean();

  if (userId !== String(req.user._id) && !User.isManager(req.user.perm)) {
    // I'm trying to write something not mine!
    return res.status(404).send({ code: server_constants.RIS_CODE_TODO_CREATING_NOTMYUSER });
  }

  try {
    if (!!myOrdersCart) {
      let fields_to_update = { status };

      await OrdersCart.findOneAndUpdate({ _id: order_id }, { $set: fields_to_update }, { new: false }).then(
        async (ris) => {
          const userDest = await User.findById(myOrdersCart.userId).lean();

          if (ris) {
            let ordertype = '';

            // Aggiorna gli Stati Interni !
            myOrdersCart = await OrdersCart.updateCmd(myOrdersCart, status, true, options);

            if ((options.hasOwnProperty('sendmail') && options.sendmail) || !options.hasOwnProperty('sendmail')) {
              if (status === shared_consts.OrderStatus.ORDER_CONFIRMED) {
                ordertype = 'order_confirmed';
              } else if (status === shared_consts.OrderStatus.DELIVERED) {
                ordertype = 'order_consegnato';
              } else if (status === shared_consts.OrderStatus.CANCELED) {
                ordertype = 'order_canceled';
              }

              if (ordertype !== '') {
                sendemail
                  .sendEmail_Order(userDest.lang, idapp, myOrdersCart, userDest, ordertype, status)
                  .then((ris) => {});
              }
            }
          }
        }
      );

      let orderscart = null;

      if (User.isManager(req.user.perm)) {
        // Prende Tutti gli Ordini !
        orderscart = await OrdersCart.getOrdersCartByUserId('ALL', idapp, 0, false);
      } else {
        orderscart = await OrdersCart.getOrdersCartByUserId(req.user.id, idapp, 0, false);
      }

      return res.send({ code: server_constants.RIS_CODE_OK, status, orders: orderscart });
    }
  } catch (e) {
    console.error('err', e);
    return res.send({ code: server_constants.RIS_CODE_ERR, status: 0 });
  }
});

//POST cart
router.post('/:userId/gestord', authenticate, async function (req, res, next) {
  let idapp = req.body.idapp;
  let idGasordine = req.body.idGasordine;

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

  try {
    let queryord = [];

    let filtroOrdini = [];

    if (idGasordine) {
      const gasordine = {
        $match: {
          idGasordine: {
            $type: 'objectId', // Checks if the field is of type ObjectId
            $eq: new mongoose.Types.ObjectId(idGasordine), // Compares the value to a specific ObjectId
          },
        },
      };
      queryord.push(gasordine);
    }

    const query = [
      {
        $lookup: {
          from: 'products',
          localField: 'idProduct',
          foreignField: '_id',
          as: 'product',
        },
      },
      {
        $unwind: {
          path: '$product',
          preserveNullAndEmptyArrays: true,
        },
      },
      {
        $lookup: {
          from: 'gasordines',
          localField: 'idGasordine',
          foreignField: '_id',
          as: 'gasordine',
        },
      },
      {
        $unwind: {
          path: '$gasordine',
          preserveNullAndEmptyArrays: true,
        },
      },
      {
        $match: {
          $or: [
            {
              quantity: {
                $gt: 0,
              },
            },
            {
              quantitypreordered: {
                $gt: 0,
              },
            },
          ],
        },
      },
      {
        $lookup: {
          from: 'orderscarts',
          localField: '_id',
          foreignField: 'items.order',
          as: 'matchingOrders',
        },
      },
      {
        $match: {
          matchingOrders: {
            $ne: [],
          },
        },
      },
      {
        $group: {
          _id: '$product._id',
          name: {
            $first: '$product.productInfo.name',
          },
          weight: {
            $first: '$product.productInfo.weight',
          },
          unit: {
            $first: '$product.productInfo.unit',
          },
          price_acquistato: {
            $first: '$product.price_acquistato',
          },
          price: {
            $first: '$product.price',
          },
          totalQuantity: {
            $sum: {
              $add: ['$quantity', '$quantitypreordered'],
            },
          },
          totalPrice_acquistato: {
            $sum: {
              $multiply: [
                '$product.price_acquistato',
                {
                  $add: ['$quantity', '$quantitypreordered'],
                },
              ],
            },
          },
          totalPrice: {
            $sum: {
              $multiply: [
                '$product.price',
                {
                  $add: ['$quantity', '$quantitypreordered'],
                },
              ],
            },
          },
          count: {
            $sum: 1,
          },
        },
      },
      {
        $sort: {
          name: 1,
        },
      },
    ];

    queryord = [...queryord, ...query];

    filtroOrdini = queryord;

    const arrout = await Order.aggregate(filtroOrdini);

    for (const rec of arrout) {
    }

    return res.send({ code: server_constants.RIS_CODE_OK, arrout });
  } catch (e) {
    console.error('Err', e);
  }
});

module.exports = router;
