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

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) {
  let userId = req.params.userId
  let idapp = req.user.idapp
  return await Cart.getCartByUserId(userId, idapp)
    .then((cart) => {
      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 });
    });

})

//POST cart
router.post('/:userId', authenticate, async function (req, res, next) {
  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;

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


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

    // const myorder = Order.getOrderByID(order._id);
    if (!addqty && !subqty && order) {
      order._id = await Order.createOrder(order);
      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 = 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 {
      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 });
    }

    /*
        Cart.updateCartByUserId(
          userId,
          newCart,
          function (err, result) {
            if (err) return next(err)
            return res.status(200).json({ cart: result })
          })
  
     */


  } 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 = 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 {

    await Cart.getCartByUserId(userId, async function (err, c) {
      if (err) return next(err)
      let oldCart = new CartClass(c || {})

      await Product.getProductByID(productId, async function (err, p) {
        if (err) return next(err)
        let newCart = oldCart.add(p, productId, { color, size })

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

    const product = await Product.getProductById(productId);

    return res.send({ code: server_constants.RIS_CODE_OK, product });
  } catch (e) {
    return res.send({ code: server_constants.RIS_CODE_ERR, status: 0 });
  }

})

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

  try {
    let mycart = await Cart.findOne({ _id: cart_id });

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

    let numorder = await OrdersCart.getLastNumOrder(idapp);
    let numord_pers = await OrdersCart.getLastNumOrdPers(userId, idapp);

    // Esiste l'ordine ?
    let myorderCart = await OrdersCart.getRecCartByUserId(userId, idapp, numorder);
    if (!myorderCart) {

      // crea il nuovo numero d'ordine
      numorder++;
      numord_pers++;

      // SE non esiste allora lo creo !
      myorderCart = new OrdersCart({
        idapp,
        items: mycart.items,
        totalQty: mycart.totalQty,
        totalPrice: mycart.totalPrice,
        totalPriceCalc: mycart.totalPriceCalc,
        note_ordine_gas: mycart.note_ordine_gas,
        userId,
        status,
        note,
        numorder,
        numord_pers,
        created_at: new Date(),
        modify_at: new Date(),
      })
    }
    statusOrderCart = myorderCart.status;
    const idordercart = myorderCart._id;

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

    if (!!mycart) {
      if (status === shared_consts.OrderStatus.CHECKOUT_SENT) {

        // Porta tutto il Cart nell'Ordine e lo CREO
        return await OrdersCart.updateOrdersCartById(-1, myorderCart, async function (err, ris) {
          //if (err) return next(err)
          if (err)
            return res.send({ code: server_constants.RIS_CODE_ERR, status: 0 });
          else {

            await Order.updateStatusOrders(mycart.items, status);

            const myris = ris;
            // Cancella il Cart appena salvato in OrdersCart

            return Cart.deleteCartByCartId(mycart._id)
              .then((ris) => {

                return OrdersCart.getOrdersCartByUserId(userId, idapp, numorder)
                  .then(async (orders) => {
                    if (!!orders) {

                      await OrdersCart.updateCmd(orders[0], status, true, req, options);

                      // Invia la email dell'Ordine
                      sendemail.sendEmail_OrderProduct(userDest.lang, idapp, orders[0], userDest)
                        .then(async (ris) => {
                          myorderCart = await OrdersCart.findById(idordercart).lean();
                          return res.send({
                            code: server_constants.RIS_CODE_OK,
                            status: myris.status,
                            orders: orders,
                            recOrderCart: myorderCart
                          });
                        });
                    }
                  });
              })
          }
        })

      }

    }
    return res.send({
      code: server_constants.RIS_CODE_OK,
      status: statusOrderCart,
      recOrderCart: myorderCart
    });
  } catch (e) {
    console.error('Err', 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;
  const user = req.user;
  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(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;
  const user = req.user;
  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: 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: 'productinfos',
          localField: 'product.idProductInfo',
          foreignField: '_id',
          as: 'productInfo',
        },
      },
      {
        $unwind: {
          path: '$productInfo',
        },
      },
      {
        $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: '$productInfo.name',
          },
          weight: {
            $first: '$productInfo.weight',
          },
          unit: {
            $first: '$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;
