var mongoose = require("mongoose");
const solr = require("solr-client");
const { updateShopperrPriceAlgo,getGlobalPrice} = require("../middlewares/priceAlgo");
const MainTag = mongoose.model("MainTag");
const {CommonDataFormator} = require("./CommonFunctions");


const connectSolr = () => {  
    const client = solr.createClient({
      host: process.env.SOLR_DEV_URL,
      port: "8983",
      core: "dsshopperr",
      path: "/solr",
    });
    return client;
};
const catUris = (cats) =>{
    return cats.map((el)=>{
        return el.toLowerCase().replace(/[^a-z0-9_-]/g,"-").replace(/-+/g,"-");
    });
}
const RemoveSeaPrice = (objArr) => {
    return objArr.map(
      ({
        seaPrice,
        varient,
        quantity,
        price,
        cogs,
        mrp,
        sp,
        selliingPrice,
        sku,
        ...otherValues
      }) => {
        const varientwithoutspace = varient?.replace(/\s/g, "") || "";
        return {
          ...otherValues,
          sku: sku === "" || !sku ? null : sku,
          varient: varientwithoutspace?.replace(/[&#,+()$~%.'":*?<>{}]/g, "") || "",
          quantity: parseInt(quantity) > 0 ? parseInt(quantity) : 0,
          price:
            parseInt(price) > 0 ? parseFloat(new Number(price).toFixed(2)) : 0,
          cogs: parseInt(cogs) > 0 ? parseFloat(new Number(cogs).toFixed(2)) : 0,
          mrp: parseInt(mrp) > 0 ? parseFloat(new Number(mrp).toFixed(2)) : 0,
          sp: parseInt(sp) > 0 ? parseFloat(new Number(sp).toFixed(2)) : 0,
          sellingPrice:
            parseInt(selliingPrice) > 0
              ? parseFloat(new Number(selliingPrice).toFixed(2))
              : 0,
        };
      }
    );
};
  
var categories = {};
async function getAsyncArrayData(product) {
    const imgUrlSrc = product.imgUrl.map(({ src }) => src);
    //console.log(product);return false;
    const options = {};
    product.options.forEach((f) => {
        switch(f.name.toLowerCase()){
        case "color":
        case "colour":
            options['color'] = f.values;
            break;
        case "size":
            options['size'] = f.values;
            break;
        case "style":
            options['style'] = f.values;
            break;
        }
    });

    const pbcd = parseFloat(product.bcd) || 10;
    const pigst = parseFloat(product.igst) || 18;
    const pswc = parseFloat(product.swcOnBcd) || 10;

    //find tags string
    const validateMongoTagsId = product.tags.filter((tg) => mongoose.isValidObjectId(tg));
	//console.log(validateMongoTagsId,product);return false;
    const maintags = await MainTag.find({
        _id: { $in: validateMongoTagsId },
    }).select("tag");

    let category = product.category;
    let cat = [product.category];
    let scat = [product.category];
    if(product.bno && categories && !categories[product.bno]){
        let browseNode = await BrowseNodes.findOne({node:Number(product.bno)});
        if(browseNode){
            categories[product.bno] = browseNode;
            let path = browseNode.path.split("/");
            scat = catUris([...path]);

            category = path.shift();
            cat = path;
        }
    }
    let slug = "";
    if(product.bno && categories[product.bno]){
        slug = categories[product.bno].slug;
        let path = categories[product.bno].path.split("/");
        scat = catUris([...path])
        category = path.shift();
        cat = path;
    }
    let tgsarra = [];
    const tagsArray = maintags.map((t) => t.tag.trim() );
    if(tagsArray){
		tgsarra = tagsArray;
	} else {
		tgsarra = [product.tgs];
	}
    const priceAlgo = updateShopperrPriceAlgo(
        Number(product.prices.STK_price) || 0,
        Number(product.weight) || 0,
        product?.spData?.price_algo || "1",
        pbcd,
        pigst,
        pswc,
        product.length,
        product.width,
        product.height,
        Number(product.mrp) || 0,
        product.productMargin
    );
	//console.log(tagsArray);return false;
    return {
        description: product.description?.replace(/<[^>]*>?/gm, "").replace(/\n/g, "")+" Sku:- "+product.code || "",
        id: product._id,
        imgUrl: imgUrlSrc,
        author: product.supplier_id,
        title: product.name,
        tags: product.tgs,
        url: product.handle,
        efp: Math.ceil(getGlobalPrice(product.price)),
        exfactoryprice: product.price,
        price: Math.round(priceAlgo.dropshipperPrice.price ? priceAlgo.dropshipperPrice.price : 0).toFixed(2),
        inStock: parseInt(product.quantity) > 0,
        sku: product.code,
        mrp: Math.round(priceAlgo.dropshipperPrice.mrp ? priceAlgo.dropshipperPrice.mrp : 0).toFixed(2),
        hsncode: product.hsn,
        weight:product.weight,
        last_modified: new Date(product.uploaded_on),
        cogs: Math.round(priceAlgo.dropshipperPrice.cogs ? priceAlgo.dropshipperPrice.cogs : 0).toFixed(2),
        content: product?.subtitle || "",
        bcd:pbcd,
        igst:pigst,
        swc: pswc,
        seaprice: Math.round(priceAlgo.seaPrice.price
        ? Number(priceAlgo.seaPrice.price)
        : 0).toFixed(2),
        seacogs: Math.round(priceAlgo.seaPrice.cogs ? Number(priceAlgo.seaPrice.cogs) : 0).toFixed(2),
        seamrp: Math.round(priceAlgo.seaPrice.mrp ? Number(priceAlgo.seaPrice.mrp) : 0).toFixed(2),
        resourcename: product?.invoicedesc || "",
        productstatus: product.pd_status,
        productmanagestatus: product.pd_manage_status,
        displaystatus: product.is_display || 0,
        size: options?.size || [],
        color: options?.color || [],
        style: options?.style || [],
        variantDescription: RemoveSeaPrice(product?.vd || []),
        variantOptions: product.options,
        tags: tgsarra,
        source: 1,
        category,
        cat,
        scat,
        channel:getDomainName({channel:product.channel}),
        slug_s:slug
    };
}

function getDomainName(product){
    return product?.channel || [];
}

async function SolrGlobalAdd(productData,action){
    if(!productData.length){
        return false;
    }
    if(!["add","update"].includes(action)){
        return false;
    }
    let toAdd = [];
    productData.forEach(async (singleProduct) => {
        if(singleProduct?.pd_status == 0){
            await deleteSolrIndexing([singleProduct]);
        } else {
            toAdd.push(getAsyncArrayData(singleProduct));
        }
    });
    if(!toAdd.length){
        return true;
    }
    toAdd = await Promise.all(toAdd);
    //console.log(toAdd);
    const client = connectSolr();
    client.autoCommit = true;
    client[action](toAdd,(err,result)=>{
      if(err)
        //throw err;
        client.softCommit();
      
    });
    return true;
}

async function deleteSolrIndexing(productData){
    if(!productData.length){
        return false;
    }
    const client = connectSolr();
    client.autoCommit = true;
    productData.forEach((singleProduct) => {
        client.delete("id",singleProduct._id.toString(),(err,result)=>{

        });
    });
    client.softCommit();
    return true;
}
const formatAllFacets = (facets)=>{
  const facetsData = {};
  Object.entries(facets).forEach(([key,facetObj])=>{
    if(key == "cat"){
      key = "cats";
    }
    facetsData[key]= makeFacetObject(facetObj);
  })
  return facetsData;
}
const makeFacetObject = (arr) => {
  let r = {};
  for (let i = 0; i < arr.length; i += 2) {
    let key = arr[i],
      value = arr[i + 1];
    r[key] = value;
  }
  return r;
};

class SolrProductDataFormator extends CommonDataFormator{
    priceAlgo = "ds";
    products = [];
    merchantId = "";
    constructor(products,merchantId){ 
      super(merchantId);
      this.products = products;
    }
    setProducts(products){
      this.products = products;
      return true;
    }
    setPriceAlgo(priceAlgo){
      this.priceAlgo = priceAlgo
      return true;
    }
    dsPrices(item){
	  let priceWithoutGst = (Math.ceil(item.price)*100)/(100+item.igst);
      let displayPrice = Math.ceil((parseFloat(item.price)));
      let gstAmount = Math.ceil(item.price - priceWithoutGst);
      //console.log(priceWithoutGst+"============"+item.mrp);return false;
      return {
        gstAmount,
        displayPrice,
        sellingPrice: item.price,
        recommendedRetailPrice: item.mrp,
      }
    }
    globalPrices(item){
      let netAmount = (100 / (parseFloat(item.igst || 18) + 100)) * parseFloat(item.efp); 
      let gstAmount = Math.ceil(parseFloat(item.efp) - netAmount).toFixed(2);
      return {
        gstAmount,
        displayPrice:item.efp,
        sellingPrice: item.price,
        recommendedRetailPrice: parseFloat(new Number(item.mrp).toFixed(2)),
      }
    } 
    getPrices(item){
      switch(this.priceAlgo){
        case "ds":
          return this.dsPrices(item);
        case "global":
            return this.globalPrices(item);
        default:
          return this.dsPrices(item); 
      }
    }
    async dataModifier(item){
		//console.log(item);return false;
      return {
        title:item.title,
        imgUrl: this.imgDataModifier(item?.imgUrl || [],item?.imgUrl?.length || 0),
        _id: item.id,
        handle: item.url,
        description:item.description,
        quantity: item.inStock,
        sku:item.sku,
        variantOptions: this.prepareVO(item.variantOptions) ?? [],
        variantDescription: this.prepareVD(item.variantDescription),
        isSubscribed: await this.isSubscribed(item.id,this.merchantId),
        ...this.getPrices(item)
      };
    }
    async formatData(){
      if(!this?.products?.length){
        return this.products
      }
      return await Promise.all(
        this.products.map(async (item) => {
          return await this.dataModifier(item);
        })
      ).then((result)=>result).catch((error)=>{
        throw error
      });
    };

}

module.exports = { SolrGlobalAdd,deleteSolrIndexing,SolrProductDataFormator,makeFacetObject,connectSolr,formatAllFacets}
