const boom = require("boom");
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken'); 
const customJwtAuth = require("../customAuthJwt");
const fastify = require("fastify")({
  logger: true,
  //disableRequestLogging: true,
  genReqId(req) {
    // you get access to the req here if you need it - must be a synchronous function
    return uuidv4();
  },
});
const { Install, ProfilePictureInstall, SensorQuotation,generateinstallationId,Store,WaterLeverSensor,MotorSwitchSenso,Insensors,generatequatationId, HardwareCart, ServiceCart, Sales} = require("../models/store");
const { User,Counter, generateBookingId,resetCounter,generateCustomerId,ProfilePicture} = require('../models/User')







exports.installSignUp = async (request, reply) => {
  try {
    const i_id = await generateinstallationId();
    const installationId = `AWIN${i_id}`;

    const {
      // name,
      phone,
      address,
      address1,
      address2,
      emails,
      password,
      profile,
      team,
      manager,
      longitude,
      latitude,
      fcmId,
      alternativeNumber,
      firstName,
      lastName,
      city,
      designation,
      reportingManager,
      departmentName,
      zone,
      createdBy,
      updatedBy,
    } = request.body;

    // Check if a user with the same phone number already exists
    const existingInstall = await Install.findOne({ phone });
    if (existingInstall) {
      return reply.status(400).send({ message: 'Phone is already registered' });
    }

    // Hash the password using bcrypt
    const hashedPassword = await bcrypt.hash(password, 10);

    // Create a new install object with the hashed password and other details
    const install = new Install({
      // name,
      installationId,
      phone,
      address,
      address1,
      address2,
      emails,
      services: { password: { bcrypt: hashedPassword } },
      profile,
      team,
      manager,
      longitude,
      latitude,
      fcmId,
      alternativeNumber,
      firstName,
      lastName,
      city,
      designation,
      reportingManager,
      departmentName,
      zone,
      createdBy,
      updatedBy,
    });

    // Save the new install to the database
    await install.save();

    reply.send({ message: 'Install Account Created Successfully' });
  } catch (err) {
    reply.status(500).send({ message: err.message });
  }
};





  
  exports.installationVerifyPhone = async (req, reply) => {
    console.log("-------------------------------------------------");
    try {
      phone = req.body.phone;
      phoneVerificationCode = req.body.phoneVerificationCode;
  
      // check if user exists in the system. If user exists , display message that
      // username is not available
      console.log(
        "this is the phone and verification code",
        phone,
        phoneVerificationCode
      );
      deliveryBoyExists = await Install.findOne({
        phone: phone,
        //phoneVerified: false,
        phoneVerificationCode: phoneVerificationCode,
      });
      console.log(deliveryBoyExists);
      if (deliveryBoyExists) {
        // update the phoneVerified flag to true.
        const filter = {
          phone: phone,
          phoneVerificationCode: phoneVerificationCode,
        };
        const update = { phoneVerified: true };
        const doc = await Install.findOneAndUpdate(filter, update);
        updatedDeliveryBoy = await Install.findOne({ phone: phone });
  
        if (updatedDeliveryBoy.phoneVerified) {
          loginObject = await supplierController.loginInstallation(req);
          console.log("loginObject...", loginObject);
          if (loginObject.same) {
            const phoneVerified = loginObject.delivery.phoneVerified;
            const oneTimePasswordSetFlag =
              loginObject.delivery.oneTimePasswordSetFlag;
            console.log(
              "oneTimePasswordSetFlag is ......",
              oneTimePasswordSetFlag,
              typeof oneTimePasswordSetFlag,
              typeof phoneVerified
            );
            if (!phoneVerified) {
              reply.send({
                simplydata: {
                  error: false,
                  phoneVerified: false,
  
                  phone: loginObject.delivery.phone,
                  oneTimePasswordSetFlag: oneTimePasswordSetFlag,
                  message: "Please Verify your phone number",
                },
              });
            } else if (oneTimePasswordSetFlag) {
              reply.send({
                simplydata: {
                  error: false,
                  phoneVerified: phoneVerified,
                  phone: loginObject.delivery.phone,
                  oneTimePasswordSetFlag: true,
                  message: "Password must be reset",
                },
              });
            } else {
              const token = fastify.jwt.sign(
                {
                  name: loginObject.delivery.name,
                },
                //expiresIn: expressed in seconds or a string describing a time span zeit/ms. Eg: 60, "2 days", "10h", "7d".
                //A numeric value is interpreted as a seconds count. If you use a string be sure you provide the time units (days, hours, etc),
                //otherwise milliseconds unit is used by default ("120" is equal to "120ms").
                { expiresIn: "30d" }
              );
              console.log(token, "..token");
  
              var d_id = loginObject.delivery._id;
  
              console.log(d_id, "deliveryId");
              var profilePicture = await ProfilePictureInstall.findOne({
                installationId: d_id,
              });
  
              // request.session.set('supplierId', loginObject.supplier._id)
  
              if (!profilePicture) {
                reply.send({
                  simplydata: {
                    error: false,
                    apiversion: fastify.config.APIVERSION,
                    access_token: token,
  
                    phone: loginObject.delivery.phone,
                    installationId: loginObject.delivery.installationId,
                    name: loginObject.delivery.name,
                    address: loginObject.delivery.address,
                    phoneVerified: loginObject.delivery.phoneVerified,
                    oneTimePasswordSetFlag:
                      loginObject.delivery.oneTimePasswordSetFlag,
                   
                   
                  },
                });
              }
              if (profilePicture) {
                reply.send({
                  simplydata: {
                    error: false,
                    apiversion: fastify.config.APIVERSION,
                    access_token: token,
                    picture: profilePicture.picture,
                    phone: loginObject.delivery.phone,
                    installationId: loginObject.delivery.installationId,

                    name: loginObject.delivery.name,
                    address: loginObject.delivery.address,
                    phoneVerified: loginObject.delivery.phoneVerified,
                    oneTimePasswordSetFlag:
                      loginObject.delivery.oneTimePasswordSetFlag,
                   
                  },
                });
              }
            }
          } else {
            error = {
              simplydata: {
                error: true,
                code: 400,
                message: "Invalid Details",
              },
            };
            reply.send(error);
          }
        } 
      }else {
        error = {
          armintatankdata: {
            error: true,
            code: 10005,
            message: "10005 - Verification code entered cannot be validated.",
          },
        };
        req.body.regError = error;
        reply.send(error);
      }
    } catch (err) {
      throw boom.boomify(err);
    }
  };


  const generateStoreId = async () => {
    const result = await Counter.findOneAndUpdate(
      { _id: 'store_id' },
      { $inc: { seq: 1 } },
      { upsert: true, new: true }
    );
    return result.seq;
  };
  const saltRounds = 10;
  const generateSalesId = async () => {
    const result = await Counter.findOneAndUpdate(
      { _id: 'sales_id' },
      { $inc: { seq: 1 } },
      { upsert: true, new: true }
    );
    return result.seq;
  };

  async function bcryptPassword(password) {
    encryptedPwd = bcrypt.hash(password, saltRounds);
    return encryptedPwd;
}

async function bcryptComparePassword(pwd, encpassword) {
    isSame = bcrypt.compare(pwd, encpassword);
    return isSame;
}



exports.addStore = async (request, reply) => {
  try {
    // Generate a unique store ID
    const s_id = await generateStoreId();
    const storeId = `AWST${s_id}`;

    const {
      storename,
      phone,
      zone,
      departmentName,
      designation,
      reportingManager,
      contactPersonName,
      contactPersonPhone,
      emails,
      password,
      description,
      startingPrice,
      longitude,
      latitude,
      fcmId,
      isActive,
      createdBy,
      updatedBy,
      profile = {}, // Default to an empty object to prevent errors
    } = request.body;
    
    const {
      firstName = null,
      lastName = null,
      contactNumber = null,
      alternativeContactNumber = null,
      store_address = null,
      city = null,
      state = null,
      zip = null,
      country = null,
      address1 = null,
      address2 = null
    } = profile; // Extract profile fields
    
    // Check if the phone is already registered
    const existingStore = await Store.findOne({ phone });
    if (existingStore) {
      return reply.status(400).send({ message: 'Phone is already registered' });
    }

    // Check if the contact person phone is already registered
    const existingContactPhone = await Store.findOne({ contactPersonPhone });
    if (existingContactPhone) {
      return reply.status(400).send({ message: 'Contact Person Phone is already registered' });
    }

    // Hash the password
    const hashedPassword = await bcrypt.hash(password, 10);

    // Create a new store document
    const store = new Store({
      storename,
      phone,
      zone,
      departmentName,
      designation,
      reportingManager,
      contactPersonName,
      contactPersonPhone,
      storeId,
      emails,
      services: { password: { bcrypt: hashedPassword } },
      description,
      startingPrice,
      profile: {
        store_address,
        firstName,
        lastName,
        contactNumber,
        alternativeContactNumber,
        city,
        state,
        zip,
        country,
        address1,
        address2
      },
      longitude,
      latitude,
      fcmId,
      isActive: isActive ?? true, // Default to true if not provided
      createdBy,
      updatedBy,
    });

    // Save the store document
    await store.save();

    reply.send({ message: 'Store Account Created Successfully' });
  } catch (err) {
    reply.status(500).send({ message: err.message });
  }
};

exports.addSales = async (request, reply) => {
  try {
    const s_id = await generateSalesId();
    const sales_id = `AWSL${s_id}`;

    const {
      phone,
      username,
      emails,
      password,
      zone,
      departmentName,
      designation,
      reportingManager,
      profile, 
      createdBy,
      updatedBy,
    } = request.body;

    const { firstName, lastName ,address,city,state,country,zip,address1,address2} = profile || {};

    const existingStore = await Sales.findOne({ phone });
    if (existingStore) {
      return reply.status(400).send({ message: 'Phone is already registered' });
    }

    const hashedPassword = await bcrypt.hash(password, 10);

    const store = new Sales({
      salesId: sales_id,
      username,
      phone,
      address,
      emails,
      zone,
      departmentName,
      designation,
      reportingManager,
      services: { password: { bcrypt: hashedPassword } },
      profile: {
        firstName, 
        lastName,  
        address,
        city,
        state,
        country,
        zip,
        address1,
        address2,
        ...profile, 
      },
      createdBy,
      updatedBy,
    });

    await store.save();

    reply.send({ message: 'Account Created Successfully' });
  } catch (err) {
    reply.status(500).send({ message: err.message });
  }
};

exports.getallsales = async (req, reply) => {
  try {
    await Sales.find()
      .exec()
      .then((docs) => {
        reply.send({ status_code: 200, data: docs, count: docs.length });
      })
      .catch((err) => {
        console.log(err);
        reply.send({ error: err });
      });
  } catch (err) {
    throw boom.boomify(err);
  }
};

exports.getallstore = async (req, reply) => {
  try {
    await Store.find()
      .exec()
      .then((docs) => {
        reply.send({ status_code: 200, data: docs, count: docs.length });
      })
      .catch((err) => {
        console.log(err);
        reply.send({ error: err });
      });
  } catch (err) {
    throw boom.boomify(err);
  }
};

exports.deleteUserInfo = async (req, reply) => {
  try {
    const salesId = req.params.salesId;
   
    const sales = await Sales.findOneAndDelete({ salesId:salesId });

    reply.send({ status_code: 200, message: 'Delete Sucessfully'});
  } catch (err) {
    throw boom.boomify(err);
  }
};
exports.deleteStoreInfo = async (req, reply) => {
  try {
    const storeId = req.params.storeId;
   
    const store = await Store.findOneAndDelete({ storeId:storeId });

    reply.send({ status_code: 200, message: 'Delete Sucessfully'});
  } catch (err) {
    throw boom.boomify(err);
  }
};

exports.editSalesUser = async (request, reply) => {
  try {
    const { salesId } = request.params;
    const {
      username,
      phone,
      emails,
      address,
      profile, 
      zone,
      reportingManager,
      designation,
      departmentName 
    } = request.body;

   
    const existingSales = await Sales.findOne({ salesId });
    if (!existingSales) {
      return reply.status(404).send({ message: 'Sales user not found' });
    }

    const phoneExists = await Sales.findOne({ phone, salesId: { $ne: salesId } });
    if (phoneExists) {
      return reply.status(400).send({ message: 'Phone is already registered to another user' });
    }

 
    existingSales.username = username || existingSales.username;
    existingSales.phone = phone || existingSales.phone;
    existingSales.emails = emails || existingSales.emails;
    existingSales.zone = zone || existingSales.zone;
    existingSales.reportingManager = reportingManager || existingSales.reportingManager;
    existingSales.designation = designation || existingSales.designation;
    existingSales.departmentName = departmentName || existingSales.departmentName;


 
    if (profile) {
      existingSales.profile.firstName = profile.firstName || existingSales.profile.firstName;
      existingSales.profile.lastName = profile.lastName || existingSales.profile.lastName;
      existingSales.profile.address = profile.address || existingSales.profile.address;
      existingSales.profile.city = profile.city || existingSales.profile.city;
      existingSales.profile.state = profile.state || existingSales.profile.state;
      existingSales.profile.country = profile.country || existingSales.profile.country;
      existingSales.profile.zip = profile.zip || existingSales.profile.zip;
      existingSales.profile.address1 = profile.address1 || existingSales.profile.address1;
      existingSales.profile.address2 = profile.address2 || existingSales.profile.address2;

    }

    
    if (request.body.password) {
      const hashedPassword = await bcrypt.hash(request.body.password, 10);
      existingSales.services.password.bcrypt = hashedPassword;
    }


    await existingSales.save();

    reply.send({ message: 'Sales user updated successfully' });
  } catch (err) {
    reply.status(500).send({ message: err.message });
  }
};

exports.editStore = async (request, reply) => {
  try {
    const { storeId } = request.params;
    const {
      storename,
      phone,
      address,
      address1,
      address2,
      emails,
      profile,
      alternativeNumber,
      longitude,
      latitude,
      fcmId,
      description,
      startingPrice,
      password,
      contactPersonPhone,
      zone,
      reportingManager,
      designation,
      departmentName
    } = request.body;

    
    const existingStore = await Store.findOne({ storeId: storeId });
    if (!existingStore) {
      return reply.status(404).send({ message: 'Store not found' });
    }

   
    const phoneExists = await Store.findOne({ phone, storeId: { $ne: storeId } });
    if (phoneExists) {
      return reply.status(400).send({ message: 'Phone is already registered to another store' });
    }

    existingStore.storename = storename || existingStore.storename;
    existingStore.phone = phone || existingStore.phone;
    existingStore.address = address || existingStore.address;
    existingStore.address1 = address1 || existingStore.address1;
    existingStore.address2 = address2 || existingStore.address2;
    existingStore.emails = emails || existingStore.emails;
    existingStore.alternativeNumber = alternativeNumber || existingStore.alternativeNumber;
    existingStore.longitude = longitude || existingStore.longitude;
    existingStore.latitude = latitude || existingStore.latitude;
    existingStore.fcmId = fcmId || existingStore.fcmId;
    existingStore.description = description || existingStore.description;
    existingStore.startingPrice = startingPrice || existingStore.startingPrice;
    existingStore.contactPersonPhone = contactPersonPhone || existingStore.contactPersonPhone;
    existingStore.zone = zone || existingStore.zone;
    existingStore.reportingManager = reportingManager || existingStore.reportingManager;
    existingStore.designation = designation || existingStore.designation;
    existingStore.departmentName = departmentName || existingStore.departmentName;

    
    if (profile) {
      existingStore.profile.firstName = profile.firstName || existingStore.profile.firstName;
      existingStore.profile.lastName = profile.lastName || existingStore.profile.lastName;
      existingStore.profile.contactNumber = profile.contactNumber || existingStore.profile.contactNumber;
      existingStore.profile.alternativeContactNumber =
        profile.alternativeContactNumber || existingStore.profile.alternativeContactNumber;
      existingStore.profile.store_address = profile.store_address || existingStore.profile.store_address;
      existingStore.profile.city = profile.city || existingStore.profile.city;
      existingStore.profile.state = profile.state || existingStore.profile.state;
      existingStore.profile.country = profile.country || existingStore.profile.country;
      existingStore.profile.zip = profile.zip || existingStore.profile.zip;
      existingStore.profile.address1 = profile.address1 || existingStore.profile.address1;
      existingStore.profile.address2 = profile.address2 || existingStore.profile.address2;

    }

    
    if (password) {
      const hashedPassword = await bcrypt.hash(password, 10);
      existingStore.services.password.bcrypt = hashedPassword;
    }

   
    await existingStore.save();

    reply.send({ message: 'Store updated successfully' });
  } catch (err) {
    reply.status(500).send({ message: err.message });
  }
};




 
  exports.getAllUsers = async (request, reply) => {
    try {
      const users = await Install.find({}); 
      reply.send(users);
    } catch (error) {
      reply.status(500).send({ message: "Error retrieving users" });
    }
  },
 
  
  exports.deleteUserByInstallationId = async (request, reply) => {
    const { installationId } = request.params;
    try {
      await Install.findOneAndDelete({ installationId });
      reply.send({ message: "User deleted successfully" });
    } catch (error) {
      reply.status(500).send({ message: "Error deleting user" });
    }
  },

 
  exports.updateUserByInstallationId = async (request, reply) => {
    const { installationId } = request.params;
    const updatedData = request.body;
    try {
      await Install.findOneAndUpdate({ installationId }, updatedData, { new: true });
      reply.send({ message: "User updated successfully" });
    } catch (error) {
      reply.status(500).send({ message: "Error updating user" });
    }
  }





  
  const generatewaterlevelsensorId = async () => {
    const result = await Counter.findOneAndUpdate(
      { _id: 'waterlevelsensor_id' },
      { $inc: { seq: 1 } },
      { upsert: true, new: true }
    );
    return result.seq;
  };

  const generatewaterlevelslavesensorId = async () => {
    const result = await Counter.findOneAndUpdate(
      { _id: 'waterlevelslavesensor_id' },
      { $inc: { seq: 1 } },
      { upsert: true, new: true }
    );
    return result.seq;
  };

  const moment = require('moment');
  exports.createwaterlevelSensor = async (req, reply) => {
    try {
      const storeId = req.params.storeId
      const { hardwareId,hardwareId_company, type, indate } = req.body;
      var mater_seq_id = await generatewaterlevelsensorId();
      const date = moment().format('MM-DD');
      const prefix = 'AS' + date + 'MALOV1';
      var masterId = `${prefix}${mater_seq_id}`;
      const newSensor = new WaterLeverSensor({
        storeId,
        hardwareId,
        masterId,
        type,
        indate
      });
      const savedSensor = await newSensor.save();
      reply.code(200).send(savedSensor);
    } catch (err) {
      reply.code(500).send(err);
    }
  };
  


  exports.editWaterLevelSensor = async (req, reply) => {
    try {
      const { storeId } = req.params;
      const updates = req.body;
  
      const updatedSensor = await WaterLeverSensor.findOneAndUpdate(
        { storeId:storeId,hardwareId: req.body.hardwareId },
        updates,
        { new: true }
      );
  
      if (!updatedSensor) {
        reply.code(404).send({ message: "Sensor not found" });
      } else {
        reply.code(200).send(updatedSensor);
      }
    } catch (err) {
      reply.code(500).send(err);
    }
  };

  exports.deleteWaterLevelSensor = async (req, reply) => {
    try {
      const { storeId } = req.params;
  
      const deletedSensor = await WaterLeverSensor.findOneAndDelete(
        { storeId,hardwareId: req.body.hardwareId }
      );
  
      if (!deletedSensor) {
        reply.code(404).send({ message: "Sensor not found" });
      } else {
        reply.code(200).send({ message: "Sensor deleted successfully" });
      }
    } catch (err) {
      reply.code(500).send(err);
    }
  };
  

  exports.installwaterlevelSensor = async (request, reply) => {
    try {
      const { storeId } = request.params;
      const updateData = request.body;
  
      // Find the document by hardwareId and update it with the fields received in the body
      const updatedSensor = await WaterLeverSensor.findOneAndUpdate(
        { storeId:storeId,hardwareId: request.body.hardwareId, },
        { $set: updateData },
        { new: true } // Return the updated document
      );
  
      if (!updatedSensor) {
        return reply.status(404).send({ error: 'Sensor not found' });
      }
  
      return reply.status(200).send(updatedSensor);
    } catch (error) {
      console.error(error);
      return reply.status(500).send({ error: 'An error occurred while updating the sensor' });
    }
  };

  exports.qccheckwaterlevelSensor = async (request, reply) => {
    try {
      const { hardwareId } = request.params;
      const updateData = request.body;
  
      // Find the document by hardwareId and update it with the fields received in the body
      const updatedSensor = await WaterLeverSensor.findOneAndUpdate(
        { hardwareId: hardwareId },
        { $set: updateData },
        { new: true } // Return the updated document
      );
  
      if (!updatedSensor) {
        return reply.status(404).send({ error: 'Sensor not found' });
      }
  
      return reply.status(200).send(updatedSensor);
    } catch (error) {
      console.error(error);
      return reply.status(500).send({ error: 'An error occurred while updating the sensor' });
    }
  };
  

  exports.getHardware = async (req, reply) => {
    try {
      await WaterLeverSensor.find({storeId: req.params.storeId})
        .exec()
        .then((docs) => {
          reply.send({ status_code: 200, data: docs, count: docs.length });
        })
        .catch((err) => {
          console.log(err);
          reply.send({ error: err });
        });
    } catch (err) {
      throw boom.boomify(err);
    }
  };
  

  exports.getHardwaremotorswitch = async (req, reply) => {
    try {
      await MotorSwitchSensor.find({storeId: req.params.storeId})
        .exec()
        .then((docs) => {
          reply.send({ status_code: 200, data: docs, count: docs.length });
        })
        .catch((err) => {
          console.log(err);
          reply.send({ error: err });
        });
    } catch (err) {
      throw boom.boomify(err);
    }
  };
  

  exports.getHardwareqc = async (req, reply) => {
    try {
      await WaterLeverSensor.find({storeId: req.params.storeId,hardwareId:req.body.hardwareId})
        .exec()
        .then((docs) => {
          reply.send({ status_code: 200, data: docs, count: docs.length });
        })
        .catch((err) => {
          console.log(err);
          reply.send({ error: err });
        });
    } catch (err) {
      throw boom.boomify(err);
    }
  };

  exports.addSlave = async (req, reply) => {
    try {
      const hardwareId = req.params.hardwareId;
      const { tankhardwareId, type, indate, hardwareId_company } = req.body;

      // Find the main hardware by hardwareId
      const mainHardware = await WaterLeverSensor.findOne({ hardwareId });

      if (!mainHardware) {
        reply.code(404).send({ message: "Main hardware not found" });
        return;
      }

      // Check if the slave's hardwareId already exists
      const existingSlave = mainHardware.slaves.tankhardware.find(slave => slave.tankhardwareId === tankhardwareId);

      if (existingSlave) {
        reply.code(400).send({ message: "Slave hardware ID already exists for this main hardware" });
        return;
      }
      var slave_seq_id = await generatewaterlevelslavesensorId();
      const date = moment().format('MM-DD');
      const prefix = 'AS' + date + 'SLAOV1';
      var slaveId = `${prefix}${slave_seq_id}`;
      // Create new slave
      const newSlave = {
        tankhardwareId,
        slaveId: slaveId, 
        type,
        indate,
        hardwareId_company
      };

      // Add the new slave to the main hardware's slaves array
      mainHardware.slaves.tankhardware.push(newSlave);

      // Save the updated main hardware
      const updatedHardware = await mainHardware.save();

      reply.code(200).send(updatedHardware);
    } catch (err) {
      reply.code(500).send(err);
    }
};



exports.editSlave = async (req, reply) => {
  try {
    const { hardwareId } = req.params;
    const updates = req.body;

    const mainHardware = await WaterLeverSensor.findOne({ hardwareId });

    if (!mainHardware) {
      reply.code(404).send({ message: "Main hardware not found" });
      return;
    }

    const slaveIndex = mainHardware.slaves.tankhardware.findIndex(
      (slave) => slave.tankhardwareId ===  req.body.tankhardwareId
    );

    if (slaveIndex === -1) {
      reply.code(404).send({ message: "Slave not found" });
      return;
    }

    mainHardware.slaves.tankhardware[slaveIndex] = {
      ...mainHardware.slaves.tankhardware[slaveIndex],
      ...updates,
    };

    const updatedHardware = await mainHardware.save();

    reply.code(200).send(updatedHardware);
  } catch (err) {
    reply.code(500).send(err);
  }
};


exports.deleteSlave = async (req, reply) => {
  try {
    const { hardwareId } = req.params;

    const mainHardware = await WaterLeverSensor.findOne({ hardwareId });

    if (!mainHardware) {
      reply.code(404).send({ message: "Main hardware not found" });
      return;
    }

    const slaveIndex = mainHardware.slaves.tankhardware.findIndex(
      (slave) => slave.tankhardwareId ===  req.body.tankhardwareId
    );

    if (slaveIndex === -1) {
      reply.code(404).send({ message: "Slave not found" });
      return;
    }

    mainHardware.slaves.tankhardware.splice(slaveIndex, 1);

    const updatedHardware = await mainHardware.save();

    reply.code(200).send(updatedHardware);
  } catch (err) {
    reply.code(500).send(err);
  }
};

exports.qccheckwaterlevelSensorSlave = async (request, reply) => {
  try {
    const { storeId } = request.params;
    const updateData = request.body;

    // Find the document by storeId and tankhardwareId, and update the corresponding slave
    const updatedSensor = await WaterLeverSensor.findOneAndUpdate(
      {
        storeId: storeId,
        hardwareId:request.body.hardwareId,
        "slaves.tankhardware.tankhardwareId": request.body.tankhardwareId
      },
      {
        $set: {
          "slaves.tankhardware.$.qccheck": updateData.qccheck,
          "slaves.tankhardware.$.qccheckdate": updateData.qccheckdate,
          "slaves.tankhardware.$.qcby": updateData.qcby,
          "slaves.tankhardware.$.comment": updateData.comment,
          "slaves.tankhardware.$.outforrepairdate": updateData.outforrepairdate,
          "slaves.tankhardware.$.sendto": updateData.sendto,
          "slaves.tankhardware.$.repairfeedback": updateData.repairfeedback
        }
      },
      { new: true } // Return the updated document
    );

    if (!updatedSensor) {
      return reply.status(404).send({ error: 'Slave not found' });
    }

    return reply.status(200).send(updatedSensor);
  } catch (error) {
    console.error(error);
    return reply.status(500).send({ error: 'An error occurred while updating the slave' });
  }
};


exports.installwaterlevelSensorSlave = async (request, reply) => {
  try {
    const { storeId } = request.params;
    const { hardwareId, tankhardwareId, dateofinstallation, customerId, installedby } = request.body;

    // Find the document by storeId and hardwareId, then update the specific slave with tankhardwareId
    const updatedSensor = await WaterLeverSensor.findOneAndUpdate(
      {
        storeId: storeId,
        hardwareId: hardwareId,
        "slaves.tankhardware.tankhardwareId": tankhardwareId
      },
      {
        $set: {
          "slaves.tankhardware.$.dateofinstallation": dateofinstallation,
          "slaves.tankhardware.$.customerId": customerId,
          "slaves.tankhardware.$.installedby": installedby
        }
      },
      { new: true } // Return the updated document
    );

    if (!updatedSensor) {
      return reply.status(404).send({ error: 'Sensor or Slave not found' });
    }

    return reply.status(200).send(updatedSensor);
  } catch (error) {
    console.error(error);
    return reply.status(500).send({ error: 'An error occurred while installing the sensor' });
  }
};

exports.getHardwareqcslave = async (req, reply) => {
  try {
    const { storeId } = req.params;
    const { hardwareId, tankhardwareId } = req.body;

    let query;
    if (tankhardwareId) {
      // If tankhardwareId is provided, query for the specific slave
      query = {
        storeId: storeId,
        hardwareId: hardwareId,
        "slaves.tankhardware.tankhardwareId": tankhardwareId,
      };
    } else {
      // Otherwise, query for the main hardware
      query = {
        storeId: storeId,
        hardwareId: hardwareId,
      };
    }

    const docs = await WaterLeverSensor.find(query).exec();

    if (docs.length === 0) {
      return reply.status(404).send({ error: 'No hardware found' });
    }

    reply.send({ status_code: 200, data: docs, count: docs.length });
  } catch (err) {
    console.error(err);
    reply.status(500).send({ error: 'An error occurred while retrieving the hardware QC data' });
  }
};

exports.createmotorswitchSensor = async (req, reply) => {
  try {
    const storeId = req.params.storeId
    const { motorId, type, indate } = req.body;
    var mater_seq_id = await generatewaterlevelsensorId();
    const date = moment().format('MM-DD');
    const prefix = 'AS' + date + 'PSV1';
    var masterId = `${prefix}${mater_seq_id}`;
    const newSensor = new MotorSwitchSensor({
      storeId,
      motorId,
      masterId,
      type,
      indate
    });
    const savedSensor = await newSensor.save();
    reply.code(200).send(savedSensor);
  } catch (err) {
    reply.code(500).send(err);
  }
};



exports.qccheckmotorswitch = async (request, reply) => {
  try {
    const { motorId } = request.params;
    const updateData = request.body;

    // Find the document by hardwareId and update it with the fields received in the body
    const updatedSensor = await MotorSwitchSensor.findOneAndUpdate(
      { motorId: motorId },
      { $set: updateData },
      { new: true } // Return the updated document
    );

    if (!updatedSensor) {
      return reply.status(404).send({ error: 'Sensor not found' });
    }

    return reply.status(200).send(updatedSensor);
  } catch (error) {
    console.error(error);
    return reply.status(500).send({ error: 'An error occurred while updating the sensor' });
  }
};


exports.installmotorswitch = async (request, reply) => {
  try {
    const { storeId } = request.params;
    const updateData = request.body;

    // Find the document by hardwareId and update it with the fields received in the body
    const updatedSensor = await MotorSwitchSensor.findOneAndUpdate(
      { storeId:storeId,motorId: request.body.motorId, },
      { $set: updateData },
      { new: true } // Return the updated document
    );

    if (!updatedSensor) {
      return reply.status(404).send({ error: 'Sensor not found' });
    }

    return reply.status(200).send(updatedSensor);
  } catch (error) {
    console.error(error);
    return reply.status(500).send({ error: 'An error occurred while updating the sensor' });
  }
};

exports.getpumpswitchqc = async (req, reply) => {
  try {
    await MotorSwitchSensor.find({storeId: req.params.storeId,motorId:req.body.motorId})
      .exec()
      .then((docs) => {
        reply.send({ status_code: 200, data: docs, count: docs.length });
      })
      .catch((err) => {
        console.log(err);
        reply.send({ error: err });
      });
  } catch (err) {
    throw boom.boomify(err);
  }
};




const generateBatchNo = (type, hardwareIdCompany) => {
  const date = new Date();
  const ddmmyy = `${date.getDate().toString().padStart(2, '0')}${(date.getMonth() + 1).toString().padStart(2, '0')}${date.getFullYear().toString().slice(-2)}`;
  const companyPrefix = hardwareIdCompany.slice(0, 2).toUpperCase();
  const randomNumbers = Math.floor(100 + Math.random() * 900).toString(); // 3 random digits
  if (type === 'SENSOR') {
    return `SN${ddmmyy}${companyPrefix}${randomNumbers}`;
  }
  if (type === 'SLAVE') {
    return `SL${ddmmyy}${companyPrefix}${randomNumbers}`;
  }
  if (type === 'MASTER') {
    return `MA${ddmmyy}${companyPrefix}${randomNumbers}`;
  }
  if (type === 'MOTOR_SWITCH') {
    return `MS${ddmmyy}${companyPrefix}${randomNumbers}`;
  }
  // Add other type conditions if needed
  return null;
};

exports.createSensor = async (req, reply) => {
  try { 
    const storeId = req.params.storeId;
    const { indate, batchno, hardwareId_company, quantity, model, type } = req.body;

    let finalBatchNo = batchno;

    if (batchno === 'New') {
      let isUnique = false;

      while (!isUnique) {
        finalBatchNo = generateBatchNo(type, hardwareId_company);

        // Check for uniqueness
        const existingBatchNo = await Insensors.findOne({ batchno: finalBatchNo });
        if (!existingBatchNo) {
          isUnique = true;
        }
      }
    }

    const date = moment().format('MM-DD');
    let entries = [];

    for (let i = 0; i < quantity; i++) {
      const newSensor = {
        storeId,
        model,
        batchno: finalBatchNo,
        type,
        indate,
        hardwareId_company
      };

      entries.push(newSensor);
    }

    const savedSensors = await Insensors.insertMany(entries);
    reply.code(200).send(savedSensors);
  } catch (err) {
    reply.code(500).send(err);
  }
};



exports.getbatchnumbers = async (req, reply) => {
  try {
    const { storeId, type } = req.params;

    let prefix = "";
    switch (type.toUpperCase()) {
      case "SLAVE":
        prefix = "SL";
        break;
      case "MASTER":
        prefix = "MA";
        break;
      case "SENSOR":
        prefix = "SN";
        break;
      case "MOTOR_SWITCH":
        prefix = "MS";
        break;
      default:
        reply.send({ status_code: 400, message: "Invalid type" });
        return;
    }

    await Insensors.distinct('batchno', {
      storeId: storeId,
      batchno: { $regex: `^${prefix}` },
    })
      .then((batchNumbers) => {
        reply.send({ status_code: 200, data: batchNumbers, count: batchNumbers.length });
      })
      .catch((err) => {
        console.error(err);
        reply.send({ status_code: 500, error: err });
      });
  } catch (err) {
    console.error(err);
    reply.send({ status_code: 500, error: err });
  }
};


exports.getiots = async (req, reply) => {
  try {
    const storeId = req.params.storeId;
    let type = req.params.type ? req.params.type.toUpperCase() : null;  // Convert type to uppercase

    let query = { storeId: storeId };
    
    if (type !== "ALL") {
      query.type = type;
    }

    // Fetch data based on the query
    const result = await Insensors.find(query);

    if (!result ) {
      return reply.send({ status_code: 404, error: "not found" });
    }

    reply.send({ status_code: 200, data: result });
  } catch (err) {
    throw boom.boomify(err);
  }
};

exports.getusersofParticularInstaller = async (req, reply) => {
  try {
    await User.find({installationId: req.query.InstallerId})
      .exec()
      .then((docs) => {
        reply.send({ status_code: 200, data: docs, count: docs.length });
      })
      .catch((err) => {
        console.log(err);
        reply.send({ error: err });
      });
  } catch (err) {
    throw boom.boomify(err);
  }
};


const dayjs = require('dayjs');
const utc = require('dayjs/plugin/utc');
const timezone = require('dayjs/plugin/timezone');

// Extend dayjs with UTC and timezone plugins
dayjs.extend(utc);
dayjs.extend(timezone);

exports.createquotationforSensor = async (req, reply) => {
  try {
    const i_id = await generatequatationId();
    const quatationId = `AWQU${i_id}`;
    const { installationId } = req.params;
    const { customerId, masters, slaves, sensors, motor_switches, electricals } = req.body;

    // Format electricals field
    const formattedElectricals = electricals.map((item) => ({
      type: item.type || "",
      wire: item.wire || "",
      switch: item.switch || "",
      text: item.text || "",
    }));

    // Format current date and time in IST
    const formattedDateTime = dayjs().tz("Asia/Kolkata").format('DD-MMM-YYYY - HH:mm');

    // Create a new SensorQuotation document
    const newQuotation = new SensorQuotation({
      quatationId,
      customerId: customerId,
      installationId: installationId, 
      quote_status: "sentfrominstaller",
      masters,
      slaves,
      sensors,
      motor_switches,
      electricals: formattedElectricals,
      datetime: formattedDateTime, // Add the formatted IST date and time
    });

    const savedQuotation = await newQuotation.save();

    reply.code(200).send({
      success: true,
      message: 'Quotation for sensors created successfully.',
      data: savedQuotation,
    });
  } catch (error) {
    console.error('Error creating quotation:', error);
    reply.code(500).send({
      success: false,
      message: 'Failed to create quotation for sensors.',
      error: error.message,
    });
  }
};


exports.editQuotationForSensor = async (req, reply) => {
  try {
    const { quatationId } = req.params; // Get the ID of the quotation to edit
    const { masters, slaves, sensors, motor_switches, electricals } = req.body;

    // Format electricals field
    const formattedElectricals = electricals.map((item) => ({
      type: item.type || "",
      wire: item.wire || "",
      switch: item.switch || "",
      text: item.text || "",
    }));

    // Find and update the quotation
    const updatedQuotation = await SensorQuotation.findOneAndUpdate(
      { quatationId },
      {
        masters,
        slaves,
        sensors,
        motor_switches,
        electricals: formattedElectricals,
        updated_at: dayjs().tz("Asia/Kolkata").format('DD-MMM-YYYY - HH:mm'),
      },
      { new: true } // Return the updated document
    );

    if (!updatedQuotation) {
      return reply.code(404).send({
        success: false,
        message: 'Quotation not found.',
      });
    }

    reply.code(200).send({
      success: true,
      message: 'Quotation updated successfully.',
      data: updatedQuotation,
    });
  } catch (error) {
    console.error('Error updating quotation:', error);
    reply.code(500).send({
      success: false,
      message: 'Failed to update quotation.',
      error: error.message,
    });
  }
};



exports.getallquotationdata = async (req, reply) => {
  try {
    await SensorQuotation.find({})
      .exec()
      .then((docs) => {
        reply.send({ status_code: 200, data: docs, count: docs.length });
      })
      .catch((err) => {
        console.log(err);
        reply.send({ error: err });
      });
  } catch (err) {
    throw boom.boomify(err);
  }
};



exports.saveQuotationData = async (req, reply) => {
  try {
    const { quotationId } = req.params;  // Retrieve the quotationId from the request parameters

    // Fetch the quotation data from the database
    const quotation = await SensorQuotation.findOne({ quatationId: quotationId });
    console.log(quotation)
    if (!quotation) {
      return reply.code(404).send({
        success: false,
        message: 'Quotation not found.'
      });
    }

    // Extract the price-per-unit and total price values from the request body
    const {
      masters_quantity_price, 
      masters_total_price,
      slaves_quantity_price, 
      slaves_total_price, 
      motor_switches_quantity_price, 
      motor_switches_total_price, 
      electricals_quantity_price, 
      electricals_total_price, 
      master_type_quantity_price, 
      master_type_total_price, 
      sensor_type_quantity_price, 
      sensor_type_total_price, 
      switch_type_quantity_price, 
      switch_type_total_price,
      quotation_total_price
    } = req.body;

    // Update the quotation document with the data from the request body
    quotation.masters_quantity_price = masters_quantity_price;
    quotation.masters_total_price = masters_total_price;
    quotation.slaves_quantity_price = slaves_quantity_price;
    quotation.slaves_total_price = slaves_total_price;
    quotation.motor_switches_quantity_price = motor_switches_quantity_price;
    quotation.motor_switches_total_price = motor_switches_total_price;
    quotation.electricals_quantity_price = electricals_quantity_price;
    quotation.electricals_total_price = electricals_total_price;
    quotation.master_type_quantity_price = master_type_quantity_price;
    quotation.master_type_total_price = master_type_total_price;
    quotation.sensor_type_quantity_price = sensor_type_quantity_price;
    quotation.sensor_type_total_price = sensor_type_total_price;
    quotation.switch_type_quantity_price = switch_type_quantity_price;
    quotation.switch_type_total_price = switch_type_total_price;
    quotation.qutation_total_price = quotation_total_price;

    // Save the updated document back to the database
    await quotation.save();

    // Send back the updated data
    reply.code(200).send({
      success: true,
      message: 'Quotation data saved successfully.',
      data: quotation
    });
  } catch (error) {
    console.error('Error saving quotation data to the database:', error);
    reply.code(500).send({
      success: false,
      message: 'Failed to save quotation data.',
      error: error.message,
    });
  }
};


exports.getSinleQuotationData = async (req, reply) => {
  try {
    const { quotationId } = req.params;  // Correct the parameter name

    // Fetch the quotation data from the database
    const quotation = await SensorQuotation.findOne({ quatationId: quotationId }); // Correctly referencing quotationId

    if (!quotation) {
      return reply.code(404).send({
        success: false,
        message: 'Quotation not found.'
      });
    }

    reply.code(200).send({
      success: true,
      message: 'Quotation data retrieved successfully.',
      data: quotation
    });
  } catch (error) {
    console.error('Error fetching quotation data:', error);
    reply.code(500).send({
      success: false,
      message: 'Failed to retrieve quotation data.',
      error: error.message,
    });
  }
};


exports.addToCartHardwareItems = async (req, reply) => {
  try {
    const { productId, productName, description, GST, unitPrice, quantity, totalAmount, serialId } = req.body;

    const gstAmount = (GST / 100) * totalAmount;
    const grandTotal = totalAmount + gstAmount;

    const newCartItem = new HardwareCart({
      productId,
      productName,
      description,
      GST,
      unitPrice,
      quantity,
      totalAmount,
      grandTotal, 
      serialId
    });

    const savedItem = await newCartItem.save();

    reply.code(201).send({ message: 'Item added to cart', data: savedItem });
  } catch (error) {
    console.error(error);
    reply.code(500).send({ message: 'Error adding item to cart', error });
  }
};

exports.addToCartService = async (req, reply) => {
  try {
    const { productId, productName, description, GST, unitPrice, quantity, totalAmount, serialId,installationId } = req.body;

    const gstAmount = (GST / 100) * totalAmount;
    const grandTotal = totalAmount + gstAmount;

    const newCartItem = new ServiceCart({
      installationId,
      productId,
      productName,
      description,
      GST,
      unitPrice,
      quantity,
      totalAmount,
      grandTotal, 
      serialId
    });

    const savedItem = await newCartItem.save();

    reply.code(201).send({ message: 'Item added to cart', data: savedItem });
  } catch (error) {
    console.error(error);
    reply.code(500).send({ message: 'Error adding item to cart', error });
  }
};




exports.getquotationofinstalleranduser = async (req, reply) => {
  try {
    const installationId = req.params.installationId;
    const customerId = req.body.customerId;
    
    // Find the specific tank
    const result = await SensorQuotation.find({
      installationId: installationId,
      customerId: customerId,
     
    });

    if (!result) {
      return reply.send({ status_code: 404, error: "not found" });
    }

   
    reply.send({ status_code: 200, data: result });
  } catch (err) {
    throw boom.boomify(err);
  }
};