PUT http://localhost:4000/api/laptops/6856b85b461c1f1b3f78e1fe 400 (Bad Request)
dispatchXhrRequest @ xhr.js:195
xhr @ xhr.js:15
dispatchRequest @ dispatchRequest.js:51
Promise.then
_request @ Axios.js:163
request @ Axios.js:40
httpMethod @ Axios.js:226
wrap @ bind.js:5
(anonymous) @ CRMdashboard.js:161
(anonymous) @ CRMdashboard.js:444
callCallback @ react-dom.development.js:4164
invokeGuardedCallbackDev @ react-dom.development.js:4213
invokeGuardedCallback @ react-dom.development.js:4277
invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:4291
executeDispatch @ react-dom.development.js:9041
processDispatchQueueItemsInOrder @ react-dom.development.js:9073
processDispatchQueue @ react-dom.development.js:9086
dispatchEventsForPlugins @ react-dom.development.js:9097
(anonymous) @ react-dom.development.js:9288
batchedUpdates$1 @ react-dom.development.js:26179
batchedUpdates @ react-dom.development.js:3991
dispatchEventForPluginEventSystem @ react-dom.development.js:9287
dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay @ react-dom.development.js:6465
dispatchEvent @ react-dom.development.js:6457
dispatchDiscreteEvent @ react-dom.development.js:6430
CRMdashboard.js:201  Error saving data: AxiosError {message: 'Request failed with status code 400', name: 'AxiosError', code: 'ERR_BAD_REQUEST', config: {…}, request: XMLHttpRequest, …}
(anonymous) @ CRMdashboard.js:201
await in (anonymous)
(anonymous) @ CRMdashboard.js:444
callCallback @ react-dom.development.js:4164
invokeGuardedCallbackDev @ react-dom.development.js:4213
invokeGuardedCallback @ react-dom.development.js:4277
invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:4291
executeDispatch @ react-dom.development.js:9041
processDispatchQueueItemsInOrder @ react-dom.development.js:9073
processDispatchQueue @ react-dom.development.js:9086
dispatchEventsForPlugins @ react-dom.development.js:9097
(anonymous) @ react-dom.development.js:9288
batchedUpdates$1 @ react-dom.development.js:26179
batchedUpdates @ react-dom.development.js:3991
dispatchEventForPluginEventSystem @ react-dom.development.js:9287
dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay @ react-dom.development.js:6465
dispatchEvent @ react-dom.development.js:6457
dispatchDiscreteEvent @ react-dom.development.js:6430
CRMdashboard.js:202  Error response: {errors: {…}}
(anonymous) @ CRMdashboard.js:202
await in (anonymous)
(anonymous) @ CRMdashboard.js:444
callCallback @ react-dom.development.js:4164
invokeGuardedCallbackDev @ react-dom.development.js:4213
invokeGuardedCallback @ react-dom.development.js:4277
invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:4291
executeDispatch @ react-dom.development.js:9041
processDispatchQueueItemsInOrder @ react-dom.development.js:9073
processDispatchQueue @ react-dom.development.js:9086
dispatchEventsForPlugins @ react-dom.development.js:9097
(anonymous) @ react-dom.development.js:9288
batchedUpdates$1 @ react-dom.development.js:26179
batchedUpdates @ react-dom.development.js:3991
dispatchEventForPluginEventSystem @ react-dom.development.js:9287
dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay @ react-dom.development.js:6465
dispatchEvent @ react-dom.development.js:6457
dispatchDiscreteEvent @ react-dom.development.js:6430
CRMdashboard.js:205  Validation errors: {image: 'Image is required for new laptops'}





const Laptop = require("../models/Laptop");
const { DeleteObjectCommand } = require("@aws-sdk/client-s3");
const validator = require("validator");
const s3 = require("../config/s3");
const mongoose = require("mongoose");
const axios = require("axios");
const { v4: uuidv4 } = require("uuid");

const validateLaptopInput = (data) => {
  const errors = {};

  if (!data.name || validator.isEmpty(data.name.trim())) {
    errors.name = "Laptop name is required";
  } else if (data.name.length > 100) {
    errors.name = "Name must be less than 100 characters";
  }

  if (
    !data.price ||
    isNaN(parseFloat(data.price)) ||
    parseFloat(data.price) <= 0
  ) {
    errors.price = "Valid price is required";
  }

  if (!data.processor || validator.isEmpty(data.processor.trim())) {
    errors.processor = "Processor information is required";
  }

  if (!data.RAM) {
    errors.RAM = "RAM information is required";
  }

  if (!data.mode || !["buy", "rent"].includes(data.mode)) {
    errors.mode = "Mode must be either 'buy' or 'rent'";
  }

  return {
    errors,
    isValid: Object.keys(errors).length === 0,
  };
};

const deleteFromS3 = async (imageUrl) => {
  try {
    if (!imageUrl || !validator.isURL(imageUrl)) return;

    const parsedUrl = new URL(imageUrl);
    const key = decodeURIComponent(parsedUrl.pathname.substring(1));

    const params = {
      Bucket: process.env.AWS_BUCKET_NAME,
      Key: key,
    };

    const command = new DeleteObjectCommand(params);
    await s3.send(command);
  } catch (error) {
    console.error("Error deleting from S3:", error.message);
  }
};

exports.getAllLaptops = async (req, res) => {
  try {
    const query = {};
    if (req.query.mode) {
      query.mode = req.query.mode;
    }
    if (req.query.status) {
      query.status = req.query.status;
    }

    const laptops = await Laptop.find(query);
    res.json(laptops);
  } catch (err) {
    res.status(500).json({
      message: "Failed to retrieve laptops",
      details: err.message,
    });
  }
};

exports.saveLaptop = async (req, res) => {
  try {
    const {
      id,
      name,
      processor,
      price,
      RAM,
      Storage,
      Graphic,
      Display,
      category,
      Brand,
      serialNumber,
      mode = "buy",
    } = req.body;

    const { errors, isValid } = validateLaptopInput(req.body);

    if (!isValid) {
      return res.status(400).json({ errors });
    }

    let imageUrl = "";
    let existingLaptop = null;

    if (id) {
      if (!mongoose.Types.ObjectId.isValid(id)) {
        return res.status(400).json({ message: "Invalid ID format" });
      }

      existingLaptop = await Laptop.findById(id);
      if (!existingLaptop) {
        return res.status(404).json({ message: "Laptop not found for update" });
      }

      imageUrl = existingLaptop.image || "";
    }

    if (req.file) {
      imageUrl = req.file.location;

      if (
        existingLaptop &&
        existingLaptop.image &&
        existingLaptop.image !== imageUrl
      ) {
        await deleteFromS3(existingLaptop.image);
      }
    }

    const laptopData = {
      name: name.trim(),
      processor: processor.trim(),
      price: parseFloat(price),
      RAM: RAM.trim(),
      Storage: Storage?.trim() || "",
      Graphic: Graphic?.trim() || "",
      Display: Display?.trim() || "",
      category: category?.trim() || "",
      Brand: Brand?.trim() || "",
      mode,
      serialNumber: serialNumber?.trim() || "",
    };

    if (imageUrl) {
      laptopData.image = imageUrl;
    }

    if (id) {
      const updatedLaptop = await Laptop.findByIdAndUpdate(
        id,
        { $set: laptopData },
        {
          new: true,
          runValidators: true,
        }
      );

      if (!updatedLaptop) {
        return res.status(404).json({ message: "Laptop not found for update" });
      }

      return res.status(200).json(updatedLaptop);
    } else {
      if (!imageUrl) {
        return res.status(400).json({
          errors: { image: "Image is required for new laptops" },
        });
      }

      const newLaptop = await Laptop.create({
        ...laptopData,
        status: "available", // Ensure default status on creation
      });

      return res.status(201).json(newLaptop);
    }
  } catch (err) {
    console.error("Save laptop error:", err);

    if (err.name === "ValidationError") {
      const validationErrors = {};
      Object.keys(err.errors).forEach((key) => {
        validationErrors[key] = err.errors[key].message;
      });
      return res.status(400).json({
        message: "Validation failed",
        errors: validationErrors,
      });
    }

    return res.status(500).json({
      message: "Failed to save laptop",
      details: err.message,
    });
  }
};

exports.deleteLaptop = async (req, res) => {
  try {
    const laptop = await Laptop.findById(req.params.id);

    if (!laptop) {
      return res.status(404).json({ message: "Laptop not found" });
    }

    if (laptop.image) {
      await deleteFromS3(laptop.image);
    }

    await Laptop.findByIdAndDelete(req.params.id);
    res.json({ message: "Laptop deleted successfully" });
  } catch (err) {
    res.status(500).json({
      message: "Failed to delete laptop",
      details: err.message,
    });
  }
};

exports.getLaptopFilters = async (req, res) => {
  try {
    const categorys = await Laptop.distinct("category");
    const rams = await Laptop.distinct("RAM");
    const processors = await Laptop.distinct("processor");
    const modes = await Laptop.distinct("mode");

    res.json({ categorys, rams, processors, modes });
  } catch (err) {
    res.status(500).json({
      message: "Failed to fetch filters",
      details: err.message,
    });
  }
};

exports.bulkImportLaptops = async (req, res) => {
  try {
    const { imageUrl, mode = "buy" } = req.body;
    let imageLocation = "";

    if (imageUrl) {
      try {
        const response = await axios.get(imageUrl, {
          responseType: "arraybuffer",
        });
        const buffer = response.data;

        const params = {
          Bucket: process.env.AWS_BUCKET_NAME,
          Key: `laptops/${uuidv4()}.jpg`,
          Body: buffer,
          ContentType: "image/jpeg",
        };

        const uploadResult = await s3.upload(params).promise();
        imageLocation = uploadResult.Location;
      } catch (downloadError) {
        console.warn("Image download failed:", downloadError);
      }
    }

    const newLaptop = await Laptop.create({
      ...req.body,
      image: imageLocation || req.file?.location,
      mode,
      status: "available",
    });
    res.status(201).json(newLaptop);
  } catch (error) {
    console.error("Bulk import error:", error);
    res.status(500).json({
      message: "Failed to import laptops",
      error: error.message,
    });
  }
};

exports.diagnosticRequest = async (req, res) => {
  try {
    console.log("Diagnostic request received");
    console.log("Request body:", req.body);
    console.log("Uploaded file:", req.file);

    res.status(200).json({
      message: "Diagnostic request processed successfully",
      file: req.file?.location || "No file uploaded",
    });
  } catch (err) {
    console.error("Diagnostic error:", err.message);
    res.status(500).json({
      message: "Diagnostic failed",
      details: err.message,
    });
  }
};

exports.getLaptopsByMode = async (req, res) => {
  try {
    const { mode } = req.params;
    const { status } = req.query;

    if (!mode || !["buy", "rent"].includes(mode)) {
      return res.status(400).json({ message: "Invalid mode parameter" });
    }

    const query = { mode };
    if (status && ["available", "rented", "sold"].includes(status)) {
      query.status = status;
    }

    const laptops = await Laptop.find(query);
    res.json(laptops);
  } catch (err) {
    res.status(500).json({
      message: "Failed to retrieve laptops by mode",
      details: err.message,
    });
  }
};



//but we are updating that wats the issue.