User: Task: "Create Change Password Api for User"
    Description: "Generate a Node.js Change Password Api with given dependenceis"
    Requirements:
    - Database: mongoose
    - Authentication: None specified
    - Output needed: Return only the function code as specified in dependencies
    - Dependencies: Create a function for password change. Export the function: exports.changePassword = async () => {...}, 
Accept parameters: oldPassword, newPassword (in the request body)., 
Accept parameter: userId (from the authenticated user's token)., 
Validate required fields: Ensure both oldPassword and newPassword are provided., 
Use the User model to find the user by userId., 
Compare oldPassword with the stored hashed password using bcrypt., 
If oldPassword is incorrect, respond with an error message., 
Hash the newPassword and update it in the database., 
Respond with a success message indicating password change., 
Handle errors like incorrect oldPassword, weak newPassword, or database issues.
    - Previous Code 
const mongoose = require('mongoose');
const Booking = require('./models/Booking'); // Assume there is a Booking model defined in models/Booking.js

/**
 * Check availability for a booking based on the provided dates and roomId.
 * 
 * @param {Date} checkInDate - The starting date for the booking.
 * @param {Date} checkOutDate - The ending date for the booking.
 * @param {String} roomId - The unique identifier for the room/service.
 * 
 * @returns {Object} - An object containing the availability status and a message.
 */
exports.checkAvailability = async (checkInDate, checkOutDate, roomId) => {
    try {
        // Validate required fields
        if (!checkInDate || !checkOutDate || !roomId) {
            throw new Error('Missing required fields: checkInDate, checkOutDate, and roomId are required');
        }

        // Ensure that checkInDate and checkOutDate are valid dates
        const checkIn = new Date(checkInDate);
        const checkOut = new Date(checkOutDate);
        if (isNaN(checkIn) || isNaN(checkOut)) {
            throw new Error('Invalid date format. Please provide valid checkInDate and checkOutDate.');
        }

        // Query the Booking model to find any conflicting bookings
        const existingBookings = await Booking.find({
            roomId: roomId,
            $or: [
                { checkInDate: { $lt: checkOut }, checkOutDate: { $gt: checkIn } }
            ]
        });

        if (existingBookings.length > 0) {
            // If conflicts exist, room/service is unavailable
            return {
                available: false,
                message: 'Room/Service is unavailable for the selected dates.'
            };
        }

        // If no conflicts exist, room/service is available
        return {
            available: true,
            message: 'Room/Service is available for the selected dates.'
        };
    } catch (error) {
        // Handle errors and provide feedback
        return {
            available: false,
            message: `Error checking availability: ${error.message}`
        };
    }
};

/**
 * Manage time slots for a specific date and service.
 * 
 * @param {String} date - The specific date for time slots.
 * @param {String} serviceId - The unique identifier for the service.
 * @param {Array} availableSlots - An array of proposed time slots.
 * 
 * @returns {Object} - An object containing the success message or errors encountered.
 */
exports.manageTimeSlots = async (date, serviceId, availableSlots) => {
    try {
        // Validate required fields
        if (!date || !serviceId || !Array.isArray(availableSlots)) {
            throw new Error('Missing required fields: date, serviceId, and availableSlots must be provided.');
        }

        // Ensure the date is a valid date
        const specificDate = new Date(date);
        if (isNaN(specificDate)) {
            throw new Error('Invalid date format. Please provide a valid date.');
        }

        // Check for overlapping time slots with existing bookings
        const overlappingBookings = await Booking.find({
            serviceId: serviceId,
            date: specificDate,
            timeSlot: { $in: availableSlots }
        });

        if (overlappingBookings.length > 0) {
            throw new Error('Some of the time slots overlap with existing bookings.');
        }
        
        // Use TimeSlot model to create or update available time slots
        await TimeSlot.updateOne(
            { date: specificDate, serviceId: serviceId },
            { $set: { availableSlots: availableSlots } },
            { upsert: true }
        );

        // Respond with a success message indicating available time slots
        return {
            success: true,
            message: 'Time slots successfully managed for the specified date and service.'
        };
    } catch (error) {
        // Handle errors and provide feedback
        return {
            success: false,
            message: `Error managing time slots: ${error.message}`
        };
    }
};

/**
 * Create a recurring booking based on the provided parameters.
 * 
 * @param {String} startDate - The starting date for the recurring booking.
 * @param {String} endDate - The ending date for the recurring booking.
 * @param {String} frequency - The frequency of recurrence (e.g., 'weekly', 'monthly').
 * @param {String} roomId - The unique identifier for the room/service.
 * 
 * @returns {Object} - An object containing the success message and booking details for each occurrence.
 */
exports.createRecurringBooking = async (startDate, endDate, frequency, roomId) => {
    try {
        // Validate required fields
        if (!startDate || !endDate || !frequency || !roomId) {
            throw new Error('Missing required fields: startDate, endDate, frequency, and roomId are required');
        }

        // Ensure that startDate and endDate are valid dates
        const start = new Date(startDate);
        const end = new Date(endDate);
        if (isNaN(start) || isNaN(end)) {
            throw new Error('Invalid date format. Please provide valid startDate and endDate.');
        }

        // Define a function to get the next date based on the frequency
        const getNextDate = (currentDate) => {
            const nextDate = new Date(currentDate);
            if (frequency === 'weekly') {
                nextDate.setDate(nextDate.getDate() + 7);
            } else if (frequency === 'monthly') {
                nextDate.setMonth(nextDate.getMonth() + 1);
            } else {
                throw new Error('Unsupported frequency. Use "weekly" or "monthly".');
            }
            return nextDate;
        };

        let currentDate = start;
        const bookingDetails = [];

        while (currentDate <= end) {
            // Check availability for each recurring date
            const availability = await exports.checkAvailability(currentDate, currentDate, roomId);
            if (!availability.available) {
                throw new Error(`Conflict detected: ${availability.message}`);
            }

            // Create a booking for each available recurring date
            const booking = new Booking({
                checkInDate: currentDate,
                checkOutDate: currentDate,
                roomId: roomId,
                // Add additional booking information if needed
            });

            await booking.save();
            bookingDetails.push({ bookingId: booking._id, date: currentDate });

            // Move to the next recurring date
            currentDate = getNextDate(currentDate);
        }

        // Respond with a success message containing the booking details for each occurrence
        return {
            success: true,
            message: 'Recurring bookings successfully created.',
            details: bookingDetails
        };

    } catch (error) {
        // Handle errors like conflicting bookings, invalid parameters, or database issues
        return {
            success: false,
            message: `Error creating recurring bookings: ${error.message}`
        };
    }
};

/**
 * Adds a user to the waitlist for a fully booked date range.
 *
 * @param {String} userId - The unique identifier of the user.
 * @param {Date} checkInDate - The starting date of the requested booking.
 * @param {Date} checkOutDate - The ending date of the requested booking.
 * @param {String} roomId - The unique identifier of the room/service.
 *
 * @returns {Object} - An object containing the success message or errors encountered.
 */
exports.addToWaitlist = async (userId, checkInDate, checkOutDate, roomId) => {
    try {
        // Validate required fields
        if (!userId || !checkInDate || !checkOutDate || !roomId) {
            throw new Error('Missing required fields: userId, checkInDate, checkOutDate, and roomId are required.');
        }

        // Ensure that checkInDate and checkOutDate are valid dates
        const checkIn = new Date(checkInDate);
        const checkOut = new Date(checkOutDate);
        if (isNaN(checkIn) || isNaN(checkOut)) {
            throw new Error('Invalid date format. Please provide valid checkInDate and checkOutDate.');
        }

        // Check if the requested period is fully booked
        const existingBookings = await Booking.find({
            roomId: roomId,
            $or: [
                { checkInDate: { $lt: checkOut }, checkOutDate: { $gt: checkIn } }
            ]
        });

        if (existingBookings.length === 0) {
            throw new Error('The requested room is available for booking. No need for a waitlist.');
        }

        // Add the user to the waitlist
        const waitlistEntry = new Waitlist({
            userId: userId,
            roomId: roomId,
            checkInDate: checkIn,
            checkOutDate: checkOut,
            priority: 1 // Example of assigning a default priority
        });

        await waitlistEntry.save();

        return {
            success: true,
            message: 'User has been successfully added to the waitlist.'
        };
    } catch (error) {
        return {
            success: false,
            message: `Error adding user to waitlist: ${error.message}`
        };
    }
};

/**
 * Create a recurring booking based on the provided parameters.
 * 
 * @param {String} startDate - The starting date for the recurring booking.
 * @param {String} endDate - The ending date for the recurring booking.
 * @param {String} frequency - The frequency of recurrence (e.g., 'weekly', 'monthly').
 * @param {String} roomId - The unique identifier for the room/service.
 * 
 * @returns {Object} - An object containing the success message and booking details for each occurrence.
 */
exports.createRecurringBooking = async (startDate, endDate, frequency, roomId) => {
    try {
        // Validate required fields
        if (!startDate || !endDate || !frequency || !roomId) {
            throw new Error('Missing required fields: startDate, endDate, frequency, and roomId are required');
        }

        // Ensure that startDate and endDate are valid dates
        const start = new Date(startDate);
        const end = new Date(endDate);
        if (isNaN(start) || isNaN(end)) {
            throw new Error('Invalid date format. Please provide valid startDate and endDate.');
        }

        // Define a function to get the next date based on the frequency
        const getNextDate = (currentDate) => {
            const nextDate = new Date(currentDate);
            if (frequency === 'weekly') {
                nextDate.setDate(nextDate.getDate() + 7);
            } else if (frequency === 'monthly') {
                nextDate.setMonth(nextDate.getMonth() + 1);
            } else {
                throw new Error('Unsupported frequency. Use "weekly" or "monthly".');
            }
            return nextDate;
        };

        let currentDate = start;
        const bookingDetails = [];

        while (currentDate <= end) {
            // Check availability for each recurring date
            const availability = await exports.checkAvailability(currentDate, currentDate, roomId);
            if (!availability.available) {
                throw new Error(`Conflict detected: ${availability.message}`);
            }

            // Create a booking for each available recurring date
            const booking = new Booking({
                checkInDate: currentDate,
                checkOutDate: currentDate,
                roomId: roomId,
                // Add additional booking information if needed
            });

            await booking.save();
            bookingDetails.push({ bookingId: booking._id, date: currentDate });

            // Move to the next recurring date
            currentDate = getNextDate(currentDate);
        }

        // Respond with a success message containing the booking details for each occurrence
        return {
            success: true,
            message: 'Recurring bookings successfully created.',
            details: bookingDetails
        };

    } catch (error) {
        // Handle errors like conflicting bookings, invalid parameters, or database issues
        return {
            success: false,
            message: `Error creating recurring bookings: ${error.message}`
        };
    }
};

/**
 * Create a recurring booking based on the provided parameters.
 * 
 * @param {String} startDate - The starting date for the recurring booking.
 * @param {String} endDate - The ending date for the recurring booking.
 * @param {String} frequency - The frequency of recurrence (e.g., 'weekly', 'monthly').
 * @param {String} roomId - The unique identifier for the room/service.
 * 
 * @returns {Object} - An object containing the success message and booking details for each occurrence.
 */
exports.createRecurringBooking = async (startDate, endDate, frequency, roomId) => {
    try {
        // Validate required fields
        if (!startDate || !endDate || !frequency || !roomId) {
            throw new Error('Missing required fields: startDate, endDate, frequency, and roomId are required');
        }

        // Ensure that startDate and endDate are valid dates
        const start = new Date(startDate);
        const end = new Date(endDate);
        if (isNaN(start) || isNaN(end)) {
            throw new Error('Invalid date format. Please provide valid startDate and endDate.');
        }

        // Define a function to get the next date based on the frequency
        const getNextDate = (currentDate) => {
            const nextDate = new Date(currentDate);
            if (frequency === 'weekly') {
                nextDate.setDate(nextDate.getDate() + 7);
            } else if (frequency === 'monthly') {
                nextDate.setMonth(nextDate.getMonth() + 1);
            } else {
                throw new Error('Unsupported frequency. Use "weekly" or "monthly".');
            }
            return nextDate;
        };

        let currentDate = start;
        const bookingDetails = [];

        while (currentDate <= end) {
            // Check availability for each recurring date
            const availability = await exports.checkAvailability(currentDate, currentDate, roomId);
            if (!availability.available) {
                throw new Error(`Conflict detected: ${availability.message}`);
            }

            // Create a booking for each available recurring date
            const booking = new Booking({
                checkInDate: currentDate,
                checkOutDate: currentDate,
                roomId: roomId,
                // Add additional booking information if needed
            });

            await booking.save();
            bookingDetails.push({ bookingId: booking._id, date: currentDate });

            // Move to the next recurring date
            currentDate = getNextDate(currentDate);
        }

        // Respond with a success message containing the booking details for each occurrence
        return {
            success: true,
            message: 'Recurring bookings successfully created.',
            details: bookingDetails
        };

    } catch (error) {
        // Handle errors like conflicting bookings, invalid parameters, or database issues
        return {
            success: false,
            message: `Error creating recurring bookings: ${error.message}`
        };
    }
};

// Import necessary dependencies
const mongoose = require('mongoose');
const User = require('./models/User'); // Assume User model is defined in models/User.js

/**
 * Fetch user profile details based on userId.
 *
 * @param {String} userId - The unique identifier of the user.
 *
 * @returns {Object} - An object containing user profile details or an error message.
 */
exports.getUserProfile = async (userId) => {
   try {
       // Validate required field
       if (!userId) {
           throw new Error('UserId is required to fetch the profile.');
       }
       
       // Use the User model to find the user by userId
       const user = await User.findById(userId, '-password'); // Exclude password from the result

       if (!user) {
           throw new Error('User not found with the provided userId.');
       }

       // Successful response with user details
       return {
           success: true,
           data: user
       };
   } catch (error) {
       // Handle errors and provide feedback
       return {
           success: false,
           message: `Error fetching user profile: ${error.message}`
       };
   }
};

// Initialize multer for file handling
const storage = multer.diskStorage({
    destination: function (req, file, cb) {
        cb(null, 'uploads/'); // The file storage location
    },
    filename: function (req, file, cb) {
        cb(null, Date.now() + '-' + file.originalname); // Creating a unique filename
    }
});

const upload = multer({ storage: storage }).single('profilePicture');

/**
 * Update user profile details.
 *
 * The function updates the user details such as name, email, phone, and profilePicture
 * in the database using the User model. The userId is expected to be provided from an authenticated source.
 *
 * Validate the fields before updating: At least one field to update must be provided.
 * Verify the email is not already in use by another user if it's being updated.
 * Handle file uploads using multer when profilePicture is provided.
 * Appropriate error handling for email conflict, missing users, or database issues.
 *
 * @param {Object} req - The request object containing user details to update.
 * @param {Object} res - The response object for sending back the updated user details or error messages.
 */
exports.updateUserProfile = async (req, res) => {
    try {
        // Extract userId from presumably authenticated user's token
        const userId = req.userId;
        
        // Extract and handle fields from request body
        const { name, email, phone } = req.body;
        
        // Check if at least one field to update is provided
        if (!name && !email && !phone && !req.file) {
            return res.status(400).json({ message: 'At least one field must be provided for updating.' });
        }

        // User update object
        const updateFields = {};
        if (name) updateFields.name = name;
        if (email) updateFields.email = email;
        if (phone) updateFields.phone = phone;

        // Profile picture handling
        upload(req, res, async (err) => {
            if (err) {
                return res.status(500).json({ message: `Error uploading file: ${err.message}` });
            }

            if (req.file) {
                updateFields.profilePicture = req.file.path; // Set profilePicture path if file provided
            }

            // Check email uniqueness if email is being updated
            if (email && (await User.findOne({ email, _id: { $ne: userId } }))) {
                return res.status(400).json({ message: 'The provided email is already in use.' });
            }

            // Find the user and update the details
            const user = await User.findByIdAndUpdate(userId, updateFields, { new: true });

            if (!user) {
                return res.status(404).json({ message: 'User not found.' });
            }

            // Respond with the updated user details
            res.status(200).json({ message: 'User profile updated successfully.', data: user });
        });
    } catch (error) {
        // Handle errors and provide feedback
        res.status(500).json({ message: `Error updating user profile: ${error.message}` });
    }
};

    - Supporting data 
    - Updating File undefined
    
    Please generate the code for this task, following the instructions and including comments for clarity.
    While creating router for specifict file your have to read supporing file data and create for that 

    **Output Formats**: 

Return dependencies like this `const bcrypt = require('bcrypt');`  in this formate
```dependencies
const bcrypt = require('bcrypt');
```

Ensure this format is consistently followed in responses.
    
User: 


    
Assistant: