const mongoose = require("mongoose");
const Keyword = mongoose.model("Keyword");
let Product = mongoose.model("Products");
const solr = require('solr-client');
const axios = require("axios");
const { messageBuilder  } = require("../../apps/common/CommonFunctions")
const Maintags =mongoose.model("MainTag")
const ShopperrSubscribeProducts = mongoose.model("ShopperrSubscribeProducts");
const { updateShopperrPriceAlgo } = require("../../apps/middlewares/priceAlgo");
const connectSolr = () => {
  const client = solr.createClient({
    host: process.env.SOLR_DEV_URL,
    port: "8983",
    core: "dsshopperr",
    path: "/solr",
  });
 // console.log("+++++++++++",client)
  client.ping(function (err, obj) {
    if (err) {
      // console.log(err);
    }
  });
  return client;
};
const AWS = require('aws-sdk');
const ID = '';
const SECRET = '';
// The name of the bucket that you have created
const BUCKET_NAME = 'test-bucket';
const s3 = new AWS.S3({
    accessKeyId: 'AKIAZQ3DPSAOW34EMAWP',
    secretAccessKey: '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'
});

// const connectSolr = () => {
//   const client = solr.createClient({
//     host: process.env.SOLR_DEV_URL,
//     port: "8983",
//     core: "shopperrproducts",
//     path: "/solr",
//     timeout: 30000, 
//   });

//   client.ping((err, obj) => {
//     if (err) {
//       console.error("Solr Ping Error:", err);
//     } else {
//       console.log("Solr Ping Success:", obj);
//     }
//   });

//   return client;
// };

exports.getSingleProductByHandle = async (req, res) => {
  const connectSolr = () => {
    const client = solr.createClient({
      host: process.env.SOLR_DEV_URL,
      port: '8983',
      core: 'dsshopperr',
      path: '/solr',
      timeout: 30000,
    });
    client.ping((err, obj) => {
      if (err) {
        return messageBuilder(res, 500, req.body, 'Solr Ping Error', { error: 1 });
      }
    });
    return client;
  };

  const { url } = req.body;
  if (!url) {
    return res.status(400).json({ status: 400, msg: "Invalid Input Param" });
  }

  try {
    // Solr Connection and Query
    const solrClient = connectSolr();
    const query = `q=url:${url}&start=0&rows=1`;
    const solrUrl = `http://${process.env.SOLR_DEV_URL}:8983/solr/dsshopperr/select?defType=dismax&q=${query}`;

    let solrResponse;
    try {
      solrResponse = await axios.get(encodeURI(solrUrl));
    } catch (err) {
      console.error("Error fetching data from Solr:", err);
      return res.status(500).json({ error: "Failed to fetch data from Solr" });
    }

    const solrData = solrResponse.data.response.docs;
    if (!solrData || solrData.length === 0) {
      return res.status(404).json({ status: 404, msg: "Product not found in Solr" });
    }

    const productHandle = solrData[0].url;

    // MongoDB Query (Keep `product` constant)
    const product = await Product.findOne({ handle: productHandle });
    if (!product) {
      console.error("No product found in MongoDB for handle:", productHandle);
      return res.status(404).json({ error: "Product not found in database" });
    }

    const { sp, mrp,length,width,height,quantity} = product;

    // Prepare the response
    const dataToSend = {
      data: {
        products: formatData(solrData),
        pricing: { sp, mrp,length,width,height,quantity },
      },
    };

    return messageBuilder(res, 200, { ...req.body }, "", dataToSend);
  } catch (err) {
    console.error("Unexpected error:", err);
    return res.status(500).json({ error: "Internal Server Error" });
  }
};



// exports.topratedProducts = async (req, res) => {
//   const connectSolr = () => {
//     const client = solr.createClient({
//       host: process.env.SOLR_DEV_URL,
//       port: '8983',
//       core: 'dsshopperr',
//       path: '/solr',
//       timeout: 30000, // Increased timeout for Solr queries
//     });

//     // Ping Solr to check connection
//     client.ping((err, obj) => {
//       if (err) {
//         // console.error('Solr Ping Error:', err);
//         return messageBuilder(res, 500, req.body, 'Solr Ping Error', { error: 1 });
//       } else {
//         // console.log('Solr Ping Success:', obj);
//       }
//     });
//     return client;
//   };
//   // console.log(req.body.keyword)
//   // const keyword = "children, headset, hair spray, hanger, wireless copy remote, shark, adhesive socket, fixture, blade" //req.body.keyword || "eBay Motors";
//   const keyword = req.body.keyword?req.body.keyword:"headset,Home & Garden, hair spray, hanger, wireless copy remote, shark, adhesive socket, fixture, blade" //req.body.keyword || "eBay Motors";
  
  
//   let page = parseInt(1);
//   let limit = parseInt(5);
//   let pageNumber=1

//   let skip = (page - 1) * limit;
//   let computedVariable = "";

//   if (req.body.title) {
//     computedVariable = computedVariable + `&qf=title^4 OR`;
//   }

//   if (req.body.description) {
//     computedVariable = computedVariable + `&qf=description^2 OR`;
//   }

//   if (req.body.tags) {
//     computedVariable = computedVariable + `&qf=tags^1.5 OR`;
//   }
//   let solrUrl = `http://${process.env.SOLR_DEV_URL}:8983/solr/dsshopperr/select?defType=dismax&q=${keyword}${computedVariable}&start=${skip}&rows=${limit}`;
//   // console.log(solrUrl);
//   try {
//     const resp = await axios.get(encodeURI(solrUrl));
//     // console.log(resp);
//     const dataToSend = {
//       data: {
//         totalRecords: resp.data.response.numFound,
//         products: formatData(resp.data.response.docs)
//       },
//     };
//     //console.log(dataToSend);
//     return messageBuilder(res, 200, { ...req.body },"", dataToSend);

//     // return res.status(200).json({
//     //   numFounds: resp.data.response.numFound,
//     //   data: formatData(resp.data.response.docs),
//     // });
//   } catch (err) {
//     res.status(500).json({});
//   }
// };

// exports.topratedProducts = async (req, res) => {
//  // console.log("sdsd")
  
//   try {
//     const expectedSourceObj = { ios: 1, android: 2, web: 3 };   
//     const expectedSourceArr = Object.keys(expectedSourceObj);
//     const keyword = req.body.keyword || "*";
//     const limit = parseInt(req.body.limit);
//     const pageNumber = parseInt(req.body.pageNumber);
//     const type = parseInt(req.body.type);
//     const source = req.body.source;
//     const arrayType = [1, 2, 3, 4, 5];

//     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 });
//     }
//     try {
//       if(keyword){
//         const keywordCreated = new Keyword({
//           name: keyword,
//           source: expectedSourceObj[source.toLowerCase()],
          
//         });
        
//         await keywordCreated.save();
//       }
//     } catch (err) {
//       return messageBuilder(res, 500, { ...req.body }, err.toString(), { error: 1 });
//     }
//     const startFrom = (parseInt(pageNumber) - 1) * parseInt(limit);
//     const client = connectSolr();
//     // console.log(client);
//     let query = client
//     .createQuery();
//     if(keyword){
//       query = query.q(`%${keyword}%`);
//     }
//     query = query.start(startFrom)
//     .rows(limit);
//     // .matchFilter("color", "*")
//     // .matchFilter("size", "S")
//     // .facet({ on: true, field: "color" })
//     // .facet({ on: true, field: "size" })
//     // .facet({ on: true, field: "style" });
//     client.search(query, async function (err, obj) {
//       if (err) {
//         console.log(err);
//         throw err;
//       } else {
//         //console.log(await formatData(obj.response.docs,null))
//         const proData  = await formatData(obj.response.docs,null);
//         await Promise.all(proData.map(async (item) => {
//           //const product = await Product.find({ _id: mongoose.Types.ObjectId(item._id) },{code:1,sp:1,mrp:1});
//           return item.reduce(async(Product, x) => {
//             // Check if the array already contains the key 't'
//               //const found = tmp.find(y => y.t === x.t);
//               const found = await Product.find({ _id: mongoose.Types.ObjectId(item._id) },{code:1,sp:1,mrp:1});
//               // If it does, add 'c' together
//               if (found) {
//                 found.sp += x.sp;
//               } else {
//                 // else, add the missing entry
//                 Product.push(x);
//               }

//               return Product;
//             }, proData);
          
//         }));
//         console.log(proData);

//     // MongoDB Query (Keep `product` constant)
    

//         const dataToSend = {
//           params: {
//             keyword,
//             limit,
//             pageNumber,
//             source,
//           },
//           data: {
//             totalRecords: obj.response.numFound,
//             products: await formatData(obj.response.docs,null)
//           },
//         };
//         return messageBuilder(res, 200, { ...req.body },"", dataToSend);
//       }
//     });
//   } catch (err) {
//     return messageBuilder(res, 500, { ...req.body },err.toString(),{error:1});
//   }
// };
const isValidImageUrl = async (url) => {
  try {
    const response = await axios.head(url);
    return response.status === 200;
  } catch (err) {
    return false;
  }
};

// Batch validation for image URLs (batch size is adjustable)
const batchValidateImageUrls = async (imageUrls) => {
  const batchSize = 10; 
  let results = [];
  for (let i = 0; i < imageUrls.length; i += batchSize) {
    const batch = imageUrls.slice(i, i + batchSize);
    const batchPromises = batch.map(url => isValidImageUrl(url));
    const batchResults = await Promise.all(batchPromises);
    results = results.concat(batchResults);
  }
  return results;
};
 
 
exports.topratedProducts = async (req, res) => {
  try {
    const expectedSourceObj = { ios: 1, android: 2, web: 3 };
    const expectedSourceArr = Object.keys(expectedSourceObj);
    const keyword = req.body.keyword || "*";
    const limit = parseInt(req.body.limit);
    const pageNumber = parseInt(req.body.pageNumber);
    const type = parseInt(req.body.type);
    const source = req.body.source;
    const arrayType = [1, 2, 3, 4, 5];

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

    try {
      if (keyword) {
        const keywordCreated = new Keyword({
          name: keyword,
          source: expectedSourceObj[source.toLowerCase()],
        });

        await keywordCreated.save();
      }
    } catch (err) {
      return messageBuilder(res, 500, { ...req.body }, err.toString(), { error: 1 });
    }

    const startFrom = (parseInt(pageNumber) - 1) * parseInt(limit);
    const client = connectSolr();

    let query = client.createQuery();
    if (keyword) {
      query = query.q(`%${keyword}%`);
    }
    query = query.start(startFrom).rows(limit);

    client.search(query, async function (err, obj) {
      if (err) {
        console.log(err);
        return messageBuilder(res, 500, { ...req.body }, err.toString(), { error: 1 });
      } else {
        const proData = await formatData(obj.response.docs, null);

        const updatedProData = await Promise.all(
          proData.map(async (item) => {
            // Fetch additional details from MongoDB
            const found = await Product.find(
              { _id: mongoose.Types.ObjectId(item._id) },
              { code: 1, sp: 1, mrp: 1 }
            );

            if (found.length > 0) {
              item.sellingPrice = found[0].sp + (item.sp || 0);
              item.recommendedRetailPrice = found[0].mrp + (item.mrp || 0);
            } else {
              item.new = true;
            }

            // Validate and filter image URLs
            if (item.imgUrl && item.imgUrl.length > 0) {
              const imageUrls = item.imgUrl.map(img => img.src);
              const imageValidities = await batchValidateImageUrls(imageUrls);
              item.imgUrl = item.imgUrl.filter((_, index) => imageValidities[index]);
            }

            // Remove products with no valid images
            return item.imgUrl.length > 0 ? item : null;
          })
        );

        const filteredProData = updatedProData.filter(item => item !== null);

        const dataToSend = {
          params: {
            keyword,
            limit,
            pageNumber,
            source,
          },
          data: {
            totalRecords: obj.response.numFound,
            products: filteredProData,
          },
        };

        return messageBuilder(res, 200, { ...req.body }, "", dataToSend);
      }
    });
  } catch (err) {
    return messageBuilder(res, 500, { ...req.body }, err.toString(), { error: 1 });
  }
};


const formatData = (obj) => {
  if (obj.length > 0) {
    const formattedData = obj.map(({ imgUrl = [], ...otherValues }) => {
      // console.log(obj)
      const supplier_id = obj[0].author;

      const appendImgUrl = imgUrl.slice(0, 50).map((img) => {
        
        // console.log(supplier_id)
        
        if(supplier_id=='67405479bf97f7739fb486a0'){
          return {
            // src: `${process.env.S3_BUCKET_FILE_URL}/${img}`,
            src: `${img}`,
          };
        }else{
          return {
            src: `${process.env.S3_BUCKET_FILE_URL}/${img}`,
            // src: `${img}`,
          };
        }
       
        
      });
      const {
        title,
        id,
        url,
        description,
        inStock,
        sku,
        price,
        mrp,
        variantOptions = [],
        variantDescription = [],
        tags,
      } = otherValues;
      // let subscribedFlag = false;
      // if (merchantId && mongoose.isValidObjectId(merchantId)) {
      //   const SubscribeProduct = await ShopperrSubscribeProducts.findOne({
      //     mId: mongoose.Types.ObjectId(merchantId),
      //     pId: mongoose.Types.ObjectId(id),
      //   });
      //   if (SubscribeProduct) {
      //     subscribedFlag = true;
      //   }
      // }
      return {
        tags,
        title,
        imgUrl: appendImgUrl,
        _id: id,
        url: url,
        description,
        quantity: inStock,
        sku,
        sellingPrice: price,
        recommendedRetailPrice: parseFloat(new Number(mrp).toFixed(2)),
        variantOptions:
          variantOptions.length > 0 ? prepareVO(variantOptions) : [],
        variantDescription:
          variantDescription.length > 0 ? prepareVD(variantDescription) : [],
        // isSubscribed: merchantId ? subscribedFlag : false,
      };
    });
    return formattedData;
  } else return [];
};
const prepareVO = (variantOptions) => {
  if (variantOptions.length > 0) {
    const variantOptionsObj = variantOptions.map((obj) => {
      const removeBraces = obj.substring(1, obj.length - 1);
      const objkeypair = removeBraces.replace(/=/g, ":").replace(/ /g, "");
      const obje = objkeypair.substring(
        objkeypair.indexOf("name") + 5,
        objkeypair.indexOf("values") - 1
      );
      const value = objkeypair.substring(
        objkeypair.indexOf("values") + 7,
        objkeypair.indexOf("]") + 1
      );
      return {
        name: obje,
        values: value.replace(/[\[\]']+/g, "").split(","),
      };
    });
    return variantOptionsObj;
  } else return [];
};

const prepareVD = (variantDesc) => {
  const variantDescriptionObj = variantDesc.map((item) => {
    const makeobject = item.replace(/(\b\S+\b)=(\b\S+\b)/g, '"$1":"$2"');
    const obj = JSON.parse(makeobject);
    return obj;
  });

  const variantArrayObj = variantDescriptionObj.map(
    ({ price, mrp, sp, quantity, sellingPrice, cogs, ...other }) => {
      return {
        ...other,
        price: parseFloat(new Number(price).toFixed(2)),
        mrp: parseFloat(new Number(mrp).toFixed(2)),
        sp: parseFloat(new Number(sp).toFixed(2)),
        sellingPrice: parseFloat(new Number(sellingPrice).toFixed(2)),
        quantity: parseInt(quantity),
      };
    }
  );

  return variantArrayObj;
};


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;
};

 
 
 

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

    // Validate input parameters
    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 });
    }

    try {
      if (keyword) {
        const keywordCreated = new Keyword({
          name: keyword,
          source: expectedSourceObj[source.toLowerCase()],
        });

        await keywordCreated.save();
      }
    } catch (err) {
      return messageBuilder(res, 500, { ...req.body }, err.toString(), { error: 1 });
    }

    const startFrom = (pageNumber - 1) * limit;
    const client = connectSolr();

    let query = client.createQuery();
    if (keyword) {
      query = query.q(`%${keyword}%`);
    }
    query = query.start(startFrom).rows(limit);

    client.search(query, async function (err, obj) {
      if (err) {
        console.log(err);
        return messageBuilder(res, 500, { ...req.body }, err.toString(), { error: 1 });
      } else {
        const proData = await formatData(obj.response.docs, null);

        // Process proData and fetch additional product details from MongoDB
        const updatedProData = await Promise.all(
          proData.map(async (item) => {
            // Fetch additional details from MongoDB
            const found = await Product.find(
              { _id: mongoose.Types.ObjectId(item._id) },
              { code: 1, sp: 1, mrp: 1 }
            );

            if (found.length > 0) {
              // Update the `sp` value if found
              item.sellingPrice = found[0].sp + (item.sp || 0);
              item.recommendedRetailPrice = found[0].mrp + (item.mrp || 0);
            } else {
              // Add marker or additional data for unmatched items
              item.new = true;
            }

            // Validate image URLs in batches (in parallel)
            const imageUrls = item.imgUrl.map(img => img.src);
            const imageValidities = await batchValidateImageUrls(imageUrls);

            // Only keep valid images
            item.imgUrl = item.imgUrl.filter((_, index) => imageValidities[index]);

            // If no valid images are found, return null (removes the product)
            if (item.imgUrl.length === 0) {
              return null;
            }

            return item;
          })
        );

        // Remove null entries from the array (products with no valid images)
        const filteredProData = updatedProData.filter(item => item !== null);

        const dataToSend = {
          params: {
            keyword,
            limit,
            pageNumber,
            source,
          },
          data: {
            totalRecords: obj.response.numFound,
            products: filteredProData,
          },
        };

        return messageBuilder(res, 200, { ...req.body }, "", dataToSend);
      }
    });
  } catch (err) {
    return messageBuilder(res, 500, { ...req.body }, err.toString(), { error: 1 });
  }
};
