const solr = require("solr-client"); 
const mongoose = require("mongoose");
const Products =mongoose.model("Products")
const User = mongoose.model("User")
const CartHistory = mongoose.model("CartHistory");
const Cart = mongoose.model("Cart");
const {
  constantValues,
  mongooseConstantValues,
} = require("../../apps/common/systemConstents");
const CategoryDesc = mongoose.model("CategoryDesc")
const { updateShopperrPriceAlgo } = require("../../apps/middlewares/priceAlgo");

exports.getProductInfobyProductId= async (req,res) => { 
  try{
    let products = await getProductData(mongoose.Types.ObjectId(req.body.pId));
    if(products.length > 0){
        let productArray    = products[0];
        productArray = JSON.parse(JSON.stringify(productArray));
        let supplier       = await User.findOne({_id : mongoose.Types.ObjectId(productArray.supplier_id)});      
        let suppllierOrigin = '';
        if(supplier){
            suppllierOrigin = supplier.price_algo;
        }
        if(req.body.sku && productArray.vd){
          let vd = productArray.vd.find((v)=>v.sku == req.body.sku);
          if(vd){
            productArray.price = vd.price;
            productArray.mrp = vd.mrp;
          }
        }
        let fp      =  productArray['price'];
        let mrps    = (productArray.mrp != '') ? productArray.mrp : 0;
        let pw      = (productArray.weight != '') ? productArray.weight : 0;
        let lenght  = ( productArray.length != '') ? productArray.length : 0;
        let width   = (productArray.width != '') ? productArray.width : 0;
        let height  = (productArray.height != '') ? productArray.height : 0;
        let pbcd    = (productArray.bcd != undefined) ? productArray.bcd : 10; 
        let pigst   = (productArray.igst != undefined) ? productArray.igst : 18;
        let retailerMargin   = (productArray.productMargin != undefined) ? productArray.productMargin : 40;
        let pswc    = (productArray['swcOnBcd'] != undefined) ? productArray['swcOnBcd'] : 10; 
        let sp  = await updateShopperrPriceAlgo(Number(fp) , Number(pw) , suppllierOrigin , pbcd , pigst , pswc , lenght , width , height , mrps , retailerMargin);
        let amazonprice = (productArray.marketPlacePrice != undefined) ? productArray.marketPlacePrice : 0;
        let amazonmrp = (productArray.marketPlaceMrp != undefined) ? productArray.marketPlaceMrp : 0;
        let marketPlaceUrl = (productArray.marketPlaceUrl != undefined) ? productArray.marketPlaceUrl : "No Data Found.";
                
        let response = { 
          airPrice:{
            factoryPrice : fp,
            price : sp.airPrice.price,
            cogs  : sp.airPrice.cogs,
            mrp   : productArray.pmrp ? productArray.pmrp : (((Math.floor(((sp.airPrice.mrp) ? sp.airPrice.mrp*2 : 0).toFixed(2)/100))*100) + 99),
            priceWithoutGst : (sp.airPrice.priceWithoutGst),
            gstOnProduct    : new Number((sp.airPrice.price - sp.airPrice.priceWithoutGst).toFixed(2)).toFixed(2),
            retailerMargin  : new Number(retailerMargin).toFixed(2),
            retailerMarginPrice : (sp.airPrice.cogs*retailerMargin/100).toFixed(2),
            amazonprice : amazonprice,
            amazonmrp : amazonmrp,
            amazonMarketPlaceUrl : marketPlaceUrl,
            gstPer : pigst
          },
          dropshipperPrice:{
            factoryPrice : fp,
            price : sp.dropshipperPrice.price,
            cogs  : sp.dropshipperPrice.cogs,
            mrp   : productArray.pmrp ? productArray.pmrp : (((Math.floor(((sp.dropshipperPrice.mrp) ? sp.dropshipperPrice.mrp*2 : 0).toFixed(2)/100))*100) + 99),
            priceWithoutGst : (sp.dropshipperPrice.priceWithoutGst),
            gstOnProduct    : new Number((sp.dropshipperPrice.price - sp.dropshipperPrice.priceWithoutGst).toFixed(2)).toFixed(2),
            retailerMargin  : new Number(retailerMargin).toFixed(2),
            retailerMarginPrice : (sp.dropshipperPrice.cogs*retailerMargin/100).toFixed(2),
            amazonprice : amazonprice,
            amazonmrp : amazonmrp,
            amazonMarketPlaceUrl : marketPlaceUrl,
            gstPer : pigst
          },
          seaPrice:{
            factoryPrice : fp,
            price : sp.seaPrice.price,
            cogs  : sp.seaPrice.cogs,
            mrp   : productArray.pmrp ? productArray.pmrp : (((Math.floor(((sp.seaPrice.mrp) ? sp.seaPrice.mrp*2 : 0).toFixed(2)/100))*100) + 99),
            priceWithoutGst : (sp.seaPrice.priceWithoutGst),
            gstOnProduct    :new Number((sp.seaPrice.price - sp.seaPrice.priceWithoutGst).toFixed(2)).toFixed(2),
            retailerMargin  : new Number(retailerMargin).toFixed(2),
            retailerMarginPrice : (sp.seaPrice.cogs*retailerMargin/100).toFixed(2),
            amazonprice : amazonprice,
            amazonmrp : amazonmrp,
            amazonMarketPlaceUrl : marketPlaceUrl,
            gstPer : pigst
          }
        }  
        return res.status(200).json(response);
    }
    else{
        return res.json({"msg":"no product found"})
    }
  }
  catch(err){
      return res.status(500).json({error:err.toString()})
  } 
}


function getProductData(cond){
    return new Promise((resolve, reject) => {
        try{
            let productData =  Products.find({'_id' : cond}).limit(1);
            resolve(productData);
        }catch(err){ 
            return true;
        } 
    })
}

exports.addToCart = async (req, res) => {
  const { wholesalerId = "", accessStatus = 0, add = -1  } = req.body;
 
  if (!wholesalerId) {
    return res.status(400).json({
      InputParams: { ...req.body },
      Response: { status: 400, msg: "Invalid Input Param B" },
    });
  }
 
  const expectedSourceObj = { ios: 1, android: 2, web: 3 };
  const expectedSourceArr = Object.keys(expectedSourceObj);
 
  var merchant = await User.findOne({ _id: wholesalerId});
  if (!merchant) {
    return res.status(400).json({
      InputParams: { ...req.body },
      Response: { status: 400, msg: "Invalid Merchant N" },
    });
  }
 
  const source = req.body.source;
 
  if (!source || !expectedSourceArr.includes(source.toLowerCase())) {
    return res.status(400).json({
      InputParams: { ...req.body },
      Response: {
        status: 400,
        msg: "Invalid Input Param : source can not be null and should be one of value [android,ios,web]",
      },
    });
  }
 
  try {
    if (!accessStatus) {
      const cartDetail = await Cart.findOne(
        { merchantId: merchant._id },
        { productDetails: 1 }
      );
      if (!cartDetail) {
        return res.status(400).json({
          InputParams: { ...req.body },
          Response: { status: 400, msg: "Data Not Found" },
        });
      }
      // console.log(cartDetail);return false;
      let data = await calculateCartPrice(cartDetail.productDetails);
      return res.status(200).json({
        InputParams: { ...req.body },
        Response: { status: 200, data: data },
      });
    }
    let cartData = JSON.parse(JSON.stringify(req.body.cartData));
 
    if (!cartData) {
      return res.status(400).json({
        InputParams: { ...req.body },
        Response: { status: 400, msg: "Invalid Input Param K" },
      });
    }
 
    if (add == 1) {
      let cartDetail =
        (await Cart.findOne(
          { merchantId: merchant._id },
          { productDetails: 1 }
        )) || [];
      cartData = [...cartData, ...(cartDetail?.productDetails || [])];
    }
 
    if (add == 0) {
      let cartDetail =
        (await Cart.findOne(
          { merchantId: merchant._id },
          { productDetails: 1 }
        )) || [];
      cartData = [...(cartDetail?.productDetails || [])].filter((el) => {
        return !cartData.find((elx) => elx.sku === el.sku);
      });
    }
    let tempCart = {};
    cartData.forEach((el) => {
      tempCart[el.sku] = el;
    });
    cartData = [];
    cartData = Object.values(tempCart);
    delete tempCart;
 
    const productIds = cartData.map((item) => {
      return mongoose.Types.ObjectId(item.productId);
    });
 
    const products = await Products.find(
      { _id: { $in: productIds } },
      { _id: 1, code: 1, varientArray: 1, quantity: 1, vd: 1 }
    );
    const availabeSku = {};
    let skus = [];
    /*products.forEach((item) => {
    console.log(item);
      let skus = [];
      skus.push(item.code);
      item.varientArray.forEach((ele) => {
        skus.push(ele.sku);
      });
      availabeSku[item._id.toString()] = skus;
    });*/
    products.forEach((item) => {
      const subVariant = item.vd;
 
      if (item.quantity == 0) {
        return res.json({
          InputParams: { ...req.body },
          Response: { status: 400, msg: "Out of stock" },
        });
      } else if (subVariant) {
        cartData.map((items) => {
          subVariant.forEach((o) => {
            if (o.sku == items.sku) {
              if (Number(o.quantity) == 0) {
                return res.json({
                  InputParams: { varient_id: o.varient_id, sku: o.sku },
                  Response: { status: 400, msg: "Varient out of stock" },
                });
              }
            }
          });
        });
      }
 
      let skus = [];
      skus.push(item.code);
      if (item.varients) {
        item.varients.forEach((ele) => {
          skus.push(ele.sku);
        });
      }
 
      if (item.varientArray) {
        item.varientArray.forEach((ele) => {
          skus.push(ele.sku);
        });
      }
      availabeSku[item._id.toString()] = skus;
    });
 
    let cartInfo = [];
    let invalidDetail = [];
    cartData.forEach((ele, i) => {
      let item = availabeSku[ele.productId.trim()];
      let product = products.find((prod) => {
        return prod._id.toString() == ele.productId.trim();
      });
      let quantity = 0;
      if (!product) {
        return false;
      }
      if (product.code == ele.sku) {
        quantity = product.quantity;
      }
      if (product.vd && product.vd.length && !quantity) {
        let variantData = product.vd.find((vdData) => {
          return vdData.sku == ele.sku;
        });
        if (variantData) {
          quantity = variantData.quantity;
        }
      }
      if (
        item &&
        item.indexOf(ele.sku) != -1 &&
        ele.productId &&
        ele.quantity &&
        quantity >= ele.quantity &&
        ele.sku &&
        product
      ) {
        cartInfo.push(ele);
      } else {
        let message = "";
        if (!ele.quantity || quantity < ele.quantity) {
          message = "The Quantity is not available of product";
        }
        if (!item || (item && item.indexOf(ele.sku) == -1) || !ele.productId) {
          message = "provided sku is invalid";
        }
        if (!ele.sku) {
          message = "Please provide product sku";
        }
        if (!product) {
          message = "Product is not find";
        }
        invalidDetail.push({
          ...ele,
          msg: message,
          error: message.length > 1 ? 1 : 0,
        });
      }
    });
 
    if (invalidDetail.length) {
      return res.status(400).json({
        InputParams: { ...req.body },
        Response: {
          status: 400,
          data: invalidDetail,
          msg: "You have provided invalid detail",
        },
      });
    }
    cartDetailData = cartInfo.map((item) => {
      item.source = source;
      return item;
    });
 
    const alreadyAddedToCart = await Cart.findOne({
      merchantId: merchant._id,
    });
    let deletedFromCart = [];
    if (alreadyAddedToCart) {
      alreadyAddedToCart.productDetails.forEach((item) => {
        let ispresent = cartDetailData.find((prod) => {
          return prod.productId == item.productId;
        });
        if (ispresent == -1 || !ispresent) {
          let obj = {};
          obj.merchantId = merchant._id;
          obj.updated_on = new Date();
          obj.created_on = new Date();
          obj.productDetail = item;
          item.is_removed = 1;
          deletedFromCart.push(obj);
        }
      });
    }
    if (deletedFromCart.length) {
      await CartHistory.insertMany(deletedFromCart);
    }
 
    const update = await Cart.updateOne(
      { merchantId: merchant._id },
      {
        $set: {
          productDetails: cartDetailData,
          merchantId: merchant._id,
          [mongooseConstantValues.UPDATED_ON]: new Date(),
        },
      },
      {
        upsert: true,
      }
    );
    return res.status(200).json({
      InputParams: { ...req.body },
      Response: {
        status: 200,
        msg: "Product added in cart",
        totalItems: cartDetailData.length,
      },
    });
  } catch (err) {
    return res.status(500).json({
      InputParams: { ...req.body },
      Response: { status: 500, msg: err.toString() },
    });
  }
};

async function calculateCartPrice(productDetails) {
  const cproductIds = productDetails.map((item) => {
    return mongoose.Types.ObjectId(item.productId);
  });
 
  const allProducts = await Products.find({ _id: { $in: cproductIds } }).select(
    "_id subtitle name handle code price sp mrp quantity length width height weight hsn invoicedesc igst swcOnBcd margin bcd vd supplier_id imgUrl"
  );
  const products = {};
  allProducts.forEach((el) => {
    products[el._id.toString()] = el;
  });
  delete allProducts;
  let totalGst = 0;
  let totalPrice = 0;
  let totalShippingCost = 0;
  let totalQuntity = 0;
  const cartproducts = await Promise.all(
    productDetails.map((product) => {
      return new Promise(async (resolve, reject) => {
        let productObj = products[product.productId];
        if (!productObj) {
          return resolve({});
        }
 
        productObj = JSON.parse(JSON.stringify(productObj));
        if (productObj.vd && productObj.vd.length) {
          let vd = {};
          vd = productObj.vd.find((variant) => {
            return variant.sku == product.sku;
          });
          if (vd) {
            delete productObj.vd;
            vd.code = vd.sku;
            delete vd.sku;
            productObj = { ...productObj, ...vd };
          }
         }
        // console.log(productObj);
 
        let gst = 0;
        let sellingPrice = productObj.sp;
        productObj.price = productObj.sp;
        netAmount = productObj.sp;
 
        let shippingCost = 0;
 
        totalQuntity += parseInt(product.quantity);
        let total_amount = netAmount * parseInt(product.quantity);
        totalPrice += total_amount;
        // let imgUrl = [];
        // productObj.imgUrl.forEach((img) => {
        //   if (img) {
        //     img.src = `${process.env.S3_BUCKET_FILE_URL}/${img.src}`;
        //     imgUrl.push(img);
        //   }
        // });
        // productObj.imgUrl = imgUrl;
       
        if (productObj.imgUrl && productObj.imgUrl.length > 1) {
         // let img = productObj.imgUrl[0];
          let img = productObj.imgUrl.find(image => image.position === 1);
          if (img) {
            img.src = `${process.env.S3_BUCKET_FILE_URL}/${img.src}`;
            productObj.imgUrl = img;
          }
        } else {
          productObj.imgUrl = null;
        }
        productObj.cartQuantity = parseInt(product.quantity);
        resolve(productObj);
      });
    })
  )
    .then((data) => data)
    .catch((err) => {
      throw err;
    });
 
  return {
    products: cartproducts,
    grossAmount: totalPrice.toFixed(2),
    shippingCharges: 0,
    GST: 0,
    netAmount: totalPrice.toFixed(2),
    nproducts: productDetails.length,
    totalItems: totalQuntity,
  };
}
  
 

exports.getCategories = async (req, res) => {
  try {
    const expectedSourceObj = { ios: 1, android: 2, web: 3 };
    const expectedSourceArr = Object.keys(expectedSourceObj);
    const level = req.body.level || 1;
    const limit = req.body.limit?parseInt(req.body.limit):1;
    const pageNumber = req.body.pageNumber?parseInt(req.body.pageNumber):1;
    const type = parseInt(req.body.type);
    const source = req.body.source;
    const arrayType = [1, 2, 3, 4, 5];
    const results = {};

    if (!limit || !pageNumber || !type || !source) {
      // return messageBuilder(res, 400, { ...req.body }, "Invalid Input Param", { error: 1 });
    }
    if (!source || !expectedSourceArr.includes(source.toLowerCase())) {
      // return messageBuilder(res, 400, { ...req.body }, "Invalid Input Param : source can not be null and should be one of value [android,ios,web]", { error: 1 });
    }
    if (!arrayType.includes(type)) {
      // return messageBuilder(res, 400, { ...req.body }, "type should be in 1,2,3,4,5", { error: 1 });
    }

    const startIndex = (pageNumber - 1) * limit;
    const endIndex = pageNumber * limit;

    // let query = {code:{$exists:true},level:level};
    let query = {};
    console.log(query)
    const categoryCount = await CategoryDesc.countDocuments(query).exec();

    results.count = categoryCount;
    results.startIndex = startIndex;
    if (endIndex < categoryCount) {
      // 
      results.next = {
        page: pageNumber + 1,
        limit: limit,
      };
    }
    if (startIndex > 0) {
      results.previous = {
        page: pageNumber - 1,
        limit: limit,
      };
    }

    // console.log('category')
    // const resu = await CategoryDesc.distinct("cd_name", {})
    // console.log(resu)
    

    results.results  = await CategoryDesc.find(query,{category_id:1,cd_name:1}).sort({ _id: -1 })
    .limit(limit)
    .skip(startIndex)
    .exec();
    // return messageBuilder(res, 200, { ...req.body },"", results);
    
    return res.send({ 'error': 0, 'Response': results })
  } catch (err) {
    // return messageBuilder(res, 500, { ...req.body },err.toString(),{error:1});
    return res.send({ 'error': 1, 'Response': err.toString() })
  }
};