please make the notifcation email service and moitoring more inteliigent advacned and better fit and like more beahabipur inteliigent super advacned and complete 
"""
const { z } = require('zod');
const mongoose = require('mongoose');
const User = require('../models/User');
const Log = require('../models/Log');
const monitorService = require('../services/monitorService');
const logger = require('../utils/logger');

/**
 * Zod Schemas for Validation
 */

/**
 * Schema for updating user settings
 * Allows updating the list of URLs, monitoring time period, and email notifications.
 */
const updateSettingsSchema = z.object({
    listOfUrls: z.array(z.string().url()).optional(),
    timePeriod: z.enum(['30s', '1m', '3m', '5m', '10m', '1h']).optional(),
    emailSend: z.boolean().optional(),
});

/**
 * Schema for getting user logs with pagination
 * Validates the `page` and `limit` query parameters.
 */
const getLogsQuerySchema = z.object({
    page: z
        .string()
        .optional()
        .refine((val) => !val || /^\d+$/.test(val), {
            message: 'page must be a positive integer',
        })
        .default('1'),
    limit: z
        .string()
        .optional()
        .refine((val) => !val || (/^\d+$/.test(val) && parseInt(val) <= 1000), {
            message: 'limit must be a positive integer not exceeding 1000',
        })
        .default('20'),
});

/**
 * Zod schema for analytics parameters
 * Validates various query parameters for generating analytics reports.
 */
const analyticsSchema = z.object({
    startDate: z.string().optional().refine((date) => !date || !isNaN(Date.parse(date)), {
        message: 'startDate must be a valid ISO date string',
    }),
    endDate: z.string().optional().refine((date) => !date || !isNaN(Date.parse(date)), {
        message: 'endDate must be a valid ISO date string',
    }),
    urls: z.string().optional().refine((urls) => !urls || urls.split(',').every((url) => {
        try { new URL(url.trim()); return true; } catch { return false; }
    }), { message: 'urls must be a comma-separated list of valid URLs' }),
    statusCodes: z.string().optional().refine((codes) => !codes || codes.split(',').every(code => /^\d+$/.test(code.trim())), {
        message: 'statusCodes must be a comma-separated list of numbers',
    }),
    minResponseTime: z.string().optional().refine(rt => !rt || /^\d+$/.test(rt), {
        message: 'minResponseTime must be a number representing milliseconds',
    }),
    maxResponseTime: z.string().optional().refine(rt => !rt || /^\d+$/.test(rt), {
        message: 'maxResponseTime must be a number representing milliseconds',
    }),
    groupBy: z.enum(['hour', 'day', 'week', 'month']).optional().default('day'),
    page: z.string().optional().refine((val) => !val || /^\d+$/.test(val), {
        message: 'page must be a positive integer',
    }).default('1'),
    limit: z.string().optional().refine((val) => !val || (/^\d+$/.test(val) && parseInt(val) <= 1000), {
        message: 'limit must be an integer between 1 and 1000',
    }).default('100'),
});

/**
 * Controller Methods
 */

/**
 * Update User Settings
 * Route: PATCH /api/user/settings
 *
 * Allows users to update their monitoring settings, including the list of URLs, monitoring interval, and email notifications.
 */
exports.updateSettings = async (req, res) => {
    try {
        // Validate input data against the schema
        const parsedData = updateSettingsSchema.parse(req.body);

        // Update the user's settings in the database
        const updatedUser = await User.findByIdAndUpdate(
            req.user.id,
            { $set: parsedData },
            { new: true, runValidators: true, context: 'query' }
        );

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

        // If the user is verified, restart the monitoring service with the new settings
        if (updatedUser.verified) {
            try {
                monitorService.restartMonitoring(updatedUser);
            } catch (monitorError) {
                // Log the error and send a response if restarting monitoring fails
                logger.error('Restart Monitoring Error:', monitorError);
                return res.status(400).json({ message: monitorError.message });
            }
        } else {
            // If the user is not verified, log a warning and inform the user
            logger.warn(`User ${updatedUser.username} is not verified. Monitoring not started.`);
            return res.status(403).json({ message: 'Email not verified. Please verify your email to start monitoring.' });
        }

        // Send a success response with the updated user data
        res.status(200).json({ message: 'Settings updated successfully', user: updatedUser });
    } catch (error) {
        if (error instanceof z.ZodError) {
            // If validation fails, send a 400 response with error details
            return res.status(400).json({ errors: error.errors });
        }
        // Handle duplicate key errors (e.g., unique email or username constraints)
        if (error.code === 11000) {
            const field = Object.keys(error.keyValue)[0];
            return res.status(400).json({ message: `${field.charAt(0).toUpperCase() + field.slice(1)} already exists` });
        }
        // Log unexpected errors and send a 500 response
        logger.error('Update Settings Error:', error);
        res.status(500).json({ message: 'Server Error' });
    }
};

/**
 * Get User Logs
 * Route: GET /api/user/logs
 *
 * Retrieves the user's monitoring logs with pagination support.
 */
exports.getUserLogs = async (req, res) => {
    try {
        // Validate query parameters against the schema
        const parsedQuery = getLogsQuerySchema.parse(req.query);
        const page = parseInt(parsedQuery.page, 10);
        const limit = parseInt(parsedQuery.limit, 10);
        const skip = (page - 1) * limit;

        // Fetch logs from the database, sorted by the most recent
        const logs = await Log.find({ user: req.user.id })
                              .sort({ checkedAt: -1 })
                              .limit(limit)
                              .skip(skip)
                              .exec();

        // Get total count of logs for pagination
        const totalLogs = await Log.countDocuments({ user: req.user.id });

        // Send the logs along with pagination details
        res.status(200).json({
            totalPages: Math.ceil(totalLogs / limit),
            currentPage: page,
            logs,
        });
    } catch (error) {
        if (error instanceof z.ZodError) {
            // If validation fails, send a 400 response with error details
            return res.status(400).json({ errors: error.errors });
        }
        // Log unexpected errors and send a 500 response
        logger.error('Get User Logs Error:', error);
        res.status(500).json({ message: 'Server Error' });
    }
};

/**
 * Start Monitoring
 * Route: POST /api/user/monitor/start
 *
 * Initiates the monitoring service for the user based on their settings.
 */
exports.startMonitoring = async (req, res) => {
    try {
        const user = await User.findById(req.user.id);

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

        if (!user.verified) {
            return res.status(403).json({ message: 'Email not verified. Please verify your email to start monitoring.' });
        }

        if (!user.listOfUrls || user.listOfUrls.length === 0) {
            return res.status(400).json({ message: 'No URLs configured for monitoring. Please add URLs to your settings.' });
        }

        // Check if monitoring is already active for the user
        const isMonitoringActive = monitorService.isMonitoringActive(user._id.toString());
        if (isMonitoringActive) {
            return res.status(400).json({ message: 'Monitoring is already active for your account.' });
        }

        // Start monitoring using the monitorService
        monitorService.startMonitoring(user);

        // Send a success response
        res.status(200).json({ message: 'Monitoring started successfully.' });
    } catch (error) {
        // Log unexpected errors and send a 500 response
        logger.error('Start Monitoring Error:', error);
        res.status(500).json({ message: 'Internal server error' });
    }
};

/**
 * Stop Monitoring
 * Route: POST /api/user/monitor/stop
 *
 * Stops the monitoring service for the user.
 */
exports.stopMonitoring = async (req, res) => {
    try {
        const user = await User.findById(req.user.id);

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

        // Check if monitoring is active for the user
        const isMonitoringActive = monitorService.isMonitoringActive(user._id.toString());
        if (!isMonitoringActive) {
            return res.status(400).json({ message: 'Monitoring is not active for your account.' });
        }

        // Stop monitoring using the monitorService
        monitorService.stopMonitoring(user);

        // Send a success response
        res.status(200).json({ message: 'Monitoring stopped successfully.' });
    } catch (error) {
        // Log unexpected errors and send a 500 response
        logger.error('Stop Monitoring Error:', error);
        res.status(500).json({ message: 'Internal server error' });
    }
};

/**
 * Get Analytics
 * Route: GET /api/user/analytics
 *
 * Retrieves analytics data for the user's monitored URLs.
 */
exports.getAnalytics = async (req, res) => {
    try {
        const userId = req.user.id;

        // Validate and parse query parameters
        const parsed = analyticsSchema.parse(req.query);
        const { startDate, endDate, urls, statusCodes, minResponseTime, maxResponseTime, groupBy, page, limit } = parsed;

        // Build the match criteria for MongoDB aggregation
        const matchCriteria = { user: new mongoose.Types.ObjectId(userId) };

        if (startDate || endDate) {
            matchCriteria.checkedAt = {};
            if (startDate) {
                matchCriteria.checkedAt.$gte = new Date(startDate);
            }
            if (endDate) {
                matchCriteria.checkedAt.$lte = new Date(endDate);
            }
        }

        if (urls) {
            const urlsArray = urls.split(',').map(url => url.trim());
            matchCriteria.url = { $in: urlsArray };
        }

        if (statusCodes) {
            const statusCodesArray = statusCodes.split(',').map(code => parseInt(code.trim()));
            matchCriteria.statusCode = { $in: statusCodesArray };
        }

        if (minResponseTime || maxResponseTime) {
            matchCriteria.responseTime = {};
            if (minResponseTime) {
                matchCriteria.responseTime.$gte = parseInt(minResponseTime, 10);
            }
            if (maxResponseTime) {
                matchCriteria.responseTime.$lte = parseInt(maxResponseTime, 10);
            }
        }

        /**
         * Aggregation Pipelines
         */

        // Total Checks
        const totalChecksPromise = Log.countDocuments(matchCriteria).exec();

        // Successful Checks (2xx)
        const successfulChecksPromise = Log.countDocuments({
            ...matchCriteria,
            statusCode: { $gte: 200, $lt: 300 },
        }).exec();

        // Failed Checks (4xx and 5xx)
        const failedChecksPromise = Log.countDocuments({
            ...matchCriteria,
            statusCode: { $gte: 400 },
        }).exec();

        // Status Code Distribution
        const statusCodeDistributionPromise = Log.aggregate([
            { $match: matchCriteria },
            {
                $group: {
                    _id: '$statusCode',
                    count: { $sum: 1 },
                },
            },
            { $sort: { count: -1 } },
        ]).exec();

        // Uptime Percentage per URL
        const uptimePerUrlPromise = Log.aggregate([
            { $match: { ...matchCriteria, statusCode: { $gte: 200, $lt: 300 } } },
            {
                $group: {
                    _id: '$url',
                    successCount: { $sum: 1 },
                },
            },
            {
                $lookup: {
                    from: 'logs',
                    let: { url: '$_id' },
                    pipeline: [
                        { $match: { 
                            $expr: { $eq: ['$url', '$$url'] },
                            ...(startDate || endDate ? {
                                ...(startDate ? { $gte: ['$checkedAt', new Date(startDate)] } : {}),
                                ...(endDate ? { $lte: ['$checkedAt', new Date(endDate)] } : {}),
                            } : {})
                        } },
                        { $count: 'totalCount' },
                    ],
                    as: 'total',
                },
            },
            {
                $addFields: {
                    totalCount: { $ifNull: [{ $arrayElemAt: ['$total.totalCount', 0] }, 0] },
                },
            },
            {
                $project: {
                    _id: 1,
                    successCount: 1,
                    totalCount: 1,
                    uptimePercentage: {
                        $cond: [
                            { $eq: ['$totalCount', 0] },
                            0,
                            { $multiply: [{ $divide: ['$successCount', '$totalCount'] }, 100] },
                        ],
                    },
                },
            },
        ]).exec();

        // Checks Over Time with Average Response Time
        const checksOverTimePromise = Log.aggregate([
            { $match: matchCriteria },
            {
                $group: {
                    _id: {
                        year: { $year: '$checkedAt' },
                        month: { $month: '$checkedAt' },
                        week: { $week: '$checkedAt' },
                        day: { $dayOfMonth: '$checkedAt' },
                        hour: { $hour: '$checkedAt' },
                    },
                    count: { $sum: 1 },
                    averageResponseTime: { $avg: '$responseTime' },
                },
            },
            {
                $project: {
                    _id: 0,
                    period: getPeriodExpression(groupBy),
                    count: 1,
                    averageResponseTime: 1,
                },
            },
            {
                $group: {
                    _id: '$period',
                    total: { $sum: '$count' },
                    averageResponseTime: { $avg: '$averageResponseTime' },
                },
            },
            { $sort: { '_id': 1 } },
        ]).exec();

        // Response Time Distribution
        const responseTimeDistributionPromise = Log.aggregate([
            { $match: matchCriteria },
            {
                $bucket: {
                    groupBy: '$responseTime',
                    boundaries: [0, 100, 300, 500, 1000, 3000, 5000, Infinity],
                    default: '5000+',
                    output: {
                        count: { $sum: 1 },
                        averageResponseTime: { $avg: '$responseTime' },
                    },
                },
            },
            { $sort: { _id: 1 } },
        ]).exec();

        // Top Slowest URLs
        const topSlowestUrlsPromise = Log.aggregate([
            { $match: matchCriteria },
            {
                $group: {
                    _id: '$url',
                    averageResponseTime: { $avg: '$responseTime' },
                    totalChecks: { $sum: 1 },
                },
            },
            { $sort: { averageResponseTime: -1 } },
            { $limit: 10 },
        ]).exec();

        // Recent Issues
        const recentIssuesPromise = Log.find({
            ...matchCriteria,
            statusCode: { $gte: 400 }, // Client and Server errors
        })
            .sort({ checkedAt: -1 })
            .limit(10)
            .select('url statusCode checkedAt screenshotUrl responseTime')
            .exec();

        // Execute all aggregation promises concurrently
        const [
            totalChecks,
            successfulChecks,
            failedChecks,
            statusCodeDistribution,
            uptimePerUrl,
            checksOverTime,
            responseTimeDistribution,
            topSlowestUrls,
            recentIssues,
        ] = await Promise.all([
            totalChecksPromise,
            successfulChecksPromise,
            failedChecksPromise,
            statusCodeDistributionPromise,
            uptimePerUrlPromise,
            checksOverTimePromise,
            responseTimeDistributionPromise,
            topSlowestUrlsPromise,
            recentIssuesPromise,
        ]);

        // Calculate success and failure percentages with safe defaults
        const successPercentage = totalChecks > 0 ? (((successfulChecks / totalChecks) * 100) || 0).toFixed(2) : '0.00';
        const failurePercentage = totalChecks > 0 ? (((failedChecks / totalChecks) * 100) || 0).toFixed(2) : '0.00';

        // Structure the analytics response
        const analytics = {
            totalChecks,
            successfulChecks,
            successPercentage: `${successPercentage}%`,
            failedChecks,
            failurePercentage: `${failurePercentage}%`,
            statusCodeDistribution: statusCodeDistribution.map(item => ({
                statusCode: item._id,
                count: item.count,
                percentage: totalChecks > 0 ? `${(((item.count / totalChecks) * 100) || 0).toFixed(2)}%` : '0.00%',
            })),
            uptimePerUrl: uptimePerUrl.map(item => ({
                url: item._id,
                successCount: item.successCount,
                totalCount: item.totalCount,
                uptimePercentage: `${(item.uptimePercentage || 0).toFixed(2)}%`,
            })),
            checksOverTime: checksOverTime.map(item => ({
                period: formatPeriod(item._id, groupBy),
                count: item.total,
                averageResponseTime: `${(item.averageResponseTime || 0).toFixed(2)}ms`,
            })),
            responseTimeDistribution: responseTimeDistribution.map(item => ({
                range: formatResponseTimeRange(item._id),
                count: item.count,
                averageResponseTime: item.averageResponseTime ? `${item.averageResponseTime.toFixed(2)}ms` : 'N/A',
            })),
            topSlowestUrls: topSlowestUrls.map(item => ({
                url: item._id,
                averageResponseTime: `${(item.averageResponseTime || 0).toFixed(2)}ms`,
                totalChecks: item.totalChecks,
            })),
            recentIssues,
        };

        // Send the analytics data as a JSON response
        res.status(200).json({ analytics });
    } catch (error) {
        if (error instanceof z.ZodError) {
            // If validation fails, send a 400 response with error details
            return res.status(400).json({
                message: 'Invalid query parameters',
                errors: error.errors.map((err) => ({
                    field: err.path.join('.'),
                    message: err.message,
                })),
            });
        }

        // Log unexpected errors and send a 500 response
        logger.error('Get Analytics Error:', error);
        res.status(500).json({ message: 'Internal server error' });
    }
};

/**
 * Helper functions for formatting
 */

/**
 * Formats the period string based on the groupBy parameter.
 *
 * @param {Object} periodObj - Object containing date parts.
 * @param {string} groupBy - Grouping parameter ('hour', 'day', 'week', 'month').
 * @returns {string} - Formatted period string.
 */
const formatPeriod = (periodObj, groupBy) => {
    const { year, month, week, day, hour } = periodObj;
    switch (groupBy) {
        case 'hour':
            return `${month}/${day}/${year} ${hour}:00`;
        case 'day':
            return `${month}/${day}/${year}`;
        case 'week':
            return `Week ${week}, ${year}`;
        case 'month':
            return `${month}/${year}`;
        default:
            return `${month}/${day}/${year}`;
    }
};

/**
 * Formats the response time range for distribution buckets.
 *
 * @param {string|number} range - The range identifier from the aggregation.
 * @returns {string} - Formatted range string.
 */
const formatResponseTimeRange = (range) => {
    if (range === '5000+') return '5000+ms';
    return `${range[0]}-${range[1]}ms`;
};

/**
 * Returns the MongoDB aggregation expression based on the groupBy parameter.
 *
 * @param {string} groupBy - Grouping parameter ('hour', 'day', 'week', 'month').
 * @returns {Object} - Aggregation expression.
 */
const getPeriodExpression = (groupBy) => ({
    hour: {
        year: { $year: '$checkedAt' },
        month: { $month: '$checkedAt' },
        day: { $dayOfMonth: '$checkedAt' },
        hour: { $hour: '$checkedAt' },
    },
    day: {
        year: { $year: '$checkedAt' },
        month: { $month: '$checkedAt' },
        day: { $dayOfMonth: '$checkedAt' },
    },
    week: {
        year: { $year: '$checkedAt' },
        week: { $week: '$checkedAt' },
    },
    month: {
        year: { $year: '$checkedAt' },
        month: { $month: '$checkedAt' },
    },
}[groupBy]);
"""
"""
// routes/userRoutes.js

const express = require('express');
const router = express.Router();
const userController = require('../controllers/userController');
const authenticate = require('../middlewares/authenticate');
const ensureVerified = require('../middlewares/ensureVerified'); // We'll create this middleware

// Apply both authentication and verification checks
router.put('/settings', authenticate, ensureVerified, userController.updateSettings);
router.get('/logs', authenticate, ensureVerified, userController.getUserLogs);

// **New Routes for Monitoring Control**
router.post('/monitor/start', authenticate, ensureVerified, userController.startMonitoring);
router.post('/monitor/stop', authenticate, ensureVerified, userController.stopMonitoring);

// **New Route for Analytics**
router.get('/analytics', authenticate, ensureVerified, userController.getAnalytics);

module.exports = router;
"""
"""
// services/emailService.js

const nodemailer = require('nodemailer');
const logger = require('../utils/logger');
const path = require('path');

// Create transporter
const transporter = nodemailer.createTransport({
    service: "Gmail",
    auth: {
        user: process.env.EMAIL_USER,
        pass: process.env.EMAIL_PASS,
    },
});
  

const sendErrorNotification = async (to, url, statusCode, screenshotUrl) => {
    const subject = `🚨 Issue Detected on ${url}`;
    let htmlContent = `
        <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #e0e0e0; border-radius: 8px; background-color: #f9f9f9;">
            <h2 style="color: #e63946;">⚠️ Issue Detected on Your Website</h2>
            <p style="color: #333;">Dear User,</p>
            <p>We encountered an issue when accessing your site:</p>
            <p style="font-size: 16px;"><strong>URL:</strong> <a href="${url}" style="color: #007bff; text-decoration: none;">${url}</a></p>
            <p style="font-size: 16px;"><strong>Status Code:</strong> <span style="color: #dc3545;">${statusCode}</span></p>
            
            ${screenshotUrl ? `
                <p style="font-size: 16px;"><strong>Screenshot:</strong> 
                <a href="${screenshotUrl}" style="color: #007bff; text-decoration: none;">View Screenshot</a></p>
                <div style="text-align: center; margin-top: 10px;">
                    <img src="${screenshotUrl}" alt="Screenshot" style="max-width: 100%; border: 1px solid #ddd; border-radius: 4px;">
                </div>
            ` : ''}

            <p style="margin-top: 20px; font-size: 14px; color: #666;">Please check and resolve the issue as soon as possible to ensure uninterrupted service.</p>
            <p style="font-size: 14px; color: #666;">Best regards,</p>
            <p style="font-size: 14px; color: #333; font-weight: bold;">Your Monitoring Team</p>
        </div>
    `;

    const mailOptions = {
        from: process.env.EMAIL_USER,
        to,
        subject,
        html: htmlContent,
    };

    try {
        await transporter.sendMail(mailOptions);
        logger.info(`Sent error notification email to ${to} for ${url}`);
    } catch (error) {
        logger.error(`Failed to send email notification to ${to} for ${url}: ${error.message}`);
    }
};

const sendVerificationEmail = async (email, token) => {
    const verificationLink = `${process.env.FRONTEND_URL}/verify/${token}`;
    const subject = '🌟 Verify Your Email - Welcome to Our Service!';
    
    const htmlContent = `
        <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #e0e0e0; border-radius: 8px; background-color: #f9f9f9;">
            <h2 style="color: #28a745;">Welcome to Our Service! 🎉</h2>
            <p style="color: #333;">Hello,</p>
            <p>Thank you for signing up! Please confirm your email address to activate your account.</p>
            <div style="text-align: center; margin: 20px 0;">
                <a href="${verificationLink}" style="text-decoration: none;">
                    <button style="padding: 12px 24px; background-color: #28a745; color: #ffffff; font-size: 16px; font-weight: bold; border: none; border-radius: 5px; cursor: pointer;">
                        Verify Email
                    </button>
                </a>
            </div>
            <p style="font-size: 14px; color: #666;">If you did not sign up for this account, you can safely ignore this email.</p>
            <p style="font-size: 14px; color: #666;">Welcome aboard, and we’re excited to have you with us!</p>
            <p style="font-size: 14px; color: #333; font-weight: bold;">Best regards,</p>
            <p style="font-size: 14px; color: #333;">Your Support Team</p>
        </div>
    `;

    const mailOptions = {
        from: process.env.EMAIL_USER,
        to: email,
        subject,
        html: htmlContent,
    };

    try {
        await transporter.sendMail(mailOptions);
        logger.info(`Verification email sent to ${email}`);
    } catch (error) {
        logger.error(`Error sending verification email to ${email}: ${error.message}`);
        throw new Error('Unable to send verification email');
    }
};



module.exports = {
    sendErrorNotification,
    sendVerificationEmail,
};
"""
"""
// services/monitorService.js

const axios = require('axios');
const cron = require('node-cron');
const Log = require('../models/Log');
const User = require('../models/User'); // Required for initialization
const screenshotService = require('./screenshotService');
const emailService = require('./emailService');
const logger = require('../utils/logger');

/**
 * Helper: Convert time period to cron expression
 * Returns null for intervals that require setInterval (e.g., '10s' and '30s')
 */
const timePeriodToCron = (timePeriod) => {
    switch (timePeriod) {
        case '10s':
        case '30s':
            return null; 
        case '1m':
            return '*/1 * * * *';
        case '3m':
            return '*/3 * * * *';
        case '5m':
            return '*/5 * * * *';
        case '10m':
            return '*/10 * * * *';
        case '1h':
            return '0 * * * *';
        default:
            return '*/1 * * * *'; // Default to every minute
    }
};

/**
 * In-memory storage for active cron jobs and intervals
 * Key: User ID (String)
 * Value: cron.Job instance or setInterval ID
 */
const userJobs = new Map();
const userIntervals = new Map();

/**
 * In-memory storage for notification timers
 * Prevents sending duplicate notifications within a certain timeframe
 * Structure: { userId: { url: timeoutObject } }
 */
const notificationTimers = new Map();

/**
 * In-memory storage for user locks to prevent overlapping performChecks
 * Key: User ID (String)
 * Value: Boolean indicating if performChecks is running
 */
const userLocks = new Map();

/**
 * Performs health checks on all URLs for a given user
 *
 * @param {Object} user - User object containing monitoring details
 */
const performChecks = async (user) => {
    const userId = user._id.toString();

    // Check if performChecks is already running for this user
    if (userLocks.get(userId)) {
        logger.warn(`performChecks is already running for user ${user.username}. Skipping this interval.`);
        return;
    }

    // Acquire lock
    userLocks.set(userId, true);
    logger.info(`Starting performChecks for user ${user.username}`);

    try {
        const urlChecks = user.listOfUrls.map(async (url) => {
            let startTime, endTime, responseTime;
            try {
                startTime = Date.now();
                const response = await axios.get(url, { timeout: 10000 });
                endTime = Date.now();
                responseTime = endTime - startTime;

                const statusCode = response.status;

                // Log successful check with response time
                await logStatus(userId, url, statusCode, "None", responseTime);

                if (statusCode < 200 || statusCode >= 300) {
                    // Handle non-2xx status codes
                    await handleFailure(user, url, statusCode);
                } else {
                    // Clear any existing notification timer on success
                    clearNotificationTimer(userId, url);
                }
            } catch (error) {
                endTime = Date.now();
                responseTime = endTime - startTime;

                let statusCode = error.response ? error.response.status : 0;
                let screenshotUrl = 'None';

                try {
                    screenshotUrl = await screenshotService.takeScreenshot(url);
                    logger.info(`Screenshot captured for ${url}`);
                } catch (screenshotError) {
                    logger.error(`Failed to take screenshot for ${url}: ${screenshotError.message}`);
                }

                // Log failed check with response time and screenshot
                await logStatus(userId, url, statusCode, screenshotUrl, responseTime);

                if (!isNotificationPending(userId, url)) {
                    await emailService.sendErrorNotification(user.email, url, statusCode, screenshotUrl);
                    setNotificationTimer(userId, url, 17 * 60 * 1000); // 17 minutes
                }
            }
        });

        // Execute all URL checks concurrently and wait for all to complete
        await Promise.all(urlChecks);
    } catch (error) {
        // Catch any unexpected errors to prevent crashing
        logger.error(`Unexpected error in performChecks for user ${user.username}: ${error.message}`);
    } finally {
        // Release lock
        userLocks.set(userId, false);
        logger.info(`Completed performChecks for user ${user.username}`);
    }
};

/**
 * Handles failures by sending notifications and setting notification timers
 *
 * @param {Object} user - User object
 * @param {string} url - URL that failed the check
 * @param {number} statusCode - HTTP status code received
 */
const handleFailure = async (user, url, statusCode) => {
    const userId = user._id.toString();
    logger.warn(`URL check failed for ${url} with status code ${statusCode}`);

    if (isNotificationPending(userId, url)) {
        logger.info(`Notification already pending for ${url}. Skipping email.`);
        return;
    }

    try {
        const screenshotUrl = await screenshotService.takeScreenshot(url);
        await emailService.sendErrorNotification(user.email, url, statusCode, screenshotUrl);
        await logStatus(userId, url, statusCode, screenshotUrl);
    } catch (error) {
        logger.error(`Failed to handle failure for ${url}: ${error.message}`);
    }

    setNotificationTimer(userId, url, 17 * 60 * 1000); // 17 minutes
};

/**
 * Logs the status of a URL check to the database
 *
 * @param {string} userId - ID of the user
 * @param {string} url - URL that was checked
 * @param {number} statusCode - HTTP status code received
 * @param {string} screenshotUrl - URL of the screenshot (if any)
 * @param {number} responseTime - Response time in milliseconds
 */
const logStatus = async (userId, url, statusCode, screenshotUrl, responseTime = 0) => {
    try {
        const log = new Log({
            user: userId,
            url,
            statusCode,
            screenshotUrl,
            checkedAt: new Date(),
            responseTime,
        });
        await log.save();
        logger.info(`Logged status for ${url} with status code ${statusCode}, response time: ${responseTime}ms, and screenshot URL: ${screenshotUrl}`);
    } catch (logError) {
        logger.error(`Failed to log status for ${url}: ${logError.message}`);
    }
};

/**
 * Starts monitoring for a user based on their settings
 *
 * @param {Object} user - User object containing monitoring details
 */
const startMonitoring = (user) => {
    if (!user.verified) {
        logger.warn(`Attempted to start monitoring for unverified user: ${user.username}`);
        throw new Error('Email not verified. Please verify your email before starting monitoring.');
    }

    if (!user.listOfUrls || user.listOfUrls.length === 0) {
        logger.warn(`No URLs to monitor for user: ${user.username}`);
        return;
    }

    // Prevent duplicate monitoring by stopping existing jobs or intervals
    stopMonitoring(user);

    const cronExpression = timePeriodToCron(user.timePeriod);
    const userId = user._id.toString();

    if (cronExpression) {
        // Schedule using node-cron for minute-based or longer intervals
        const job = cron.schedule(cronExpression, () => {
            performChecks(user);
        }, {
            scheduled: true,
            timezone: "UTC",
        });

        userJobs.set(userId, job);
        logger.info(`Started cron job (${cronExpression}) monitoring for user ${user.username}`);
    } else if (user.timePeriod === '10s' || user.timePeriod === '30s') {
        // Use setInterval for second-based intervals with safeguards
        const intervalMs = user.timePeriod === '10s' ? 10 * 1000 : 30 * 1000;

        const interval = setInterval(async () => {
            try {
                await performChecks(user);
            } catch (error) {
                logger.error(`Error during performChecks for user ${user.username} at interval ${user.timePeriod}: ${error.message}`);
            }
        }, intervalMs);

        userIntervals.set(userId, interval);
        logger.info(`Started ${user.timePeriod} interval monitoring for user ${user.username}`);
    } else {
        logger.warn(`Unsupported time period "${user.timePeriod}" for user ${user.username}. Defaulting to every minute.`);
        // Defaulting to every minute if unsupported timePeriod is provided
        const defaultCron = '*/1 * * * *';
        const job = cron.schedule(defaultCron, () => {
            performChecks(user);
        }, {
            scheduled: true,
            timezone: "UTC",
        });

        userJobs.set(userId, job);
        logger.info(`Started default cron job (${defaultCron}) monitoring for user ${user.username}`);
    }
};

/**
 * Stops monitoring for a user by clearing their cron job or interval
 *
 * @param {Object} user - User object
 */
const stopMonitoring = (user) => {
    const userId = user._id.toString();

    if (userJobs.has(userId)) {
        const job = userJobs.get(userId);
        job.stop();
        userJobs.delete(userId);
        logger.info(`Stopped cron job monitoring for user ${user.username}`);
    }

    if (userIntervals.has(userId)) {
        clearInterval(userIntervals.get(userId));
        userIntervals.delete(userId);
        logger.info(`Stopped interval monitoring for user ${user.username}`);
    }

    // Clear any pending notification timers
    if (notificationTimers.has(userId)) {
        const userTimers = notificationTimers.get(userId);
        for (const url in userTimers) {
            clearTimeout(userTimers[url]);
            logger.info(`Cleared notification timer for ${url} (User: ${user.username})`);
        }
        notificationTimers.delete(userId);
    }

    // Release any locks if present
    if (userLocks.has(userId)) {
        userLocks.delete(userId);
    }
};

/**
 * Restarts monitoring for a user by stopping existing monitoring and starting anew
 *
 * @param {Object} user - User object
 */
const restartMonitoring = (user) => {
    if (!user.verified) {
        logger.warn(`Attempted to restart monitoring for unverified user: ${user.username}`);
        throw new Error('Email not verified. Please verify your email before restarting monitoring.');
    }
    stopMonitoring(user);
    startMonitoring(user);
};

/**
 * Checks if monitoring is active for a given user
 *
 * @param {string} userId - ID of the user
 * @returns {boolean} - True if monitoring is active, else false
 */
const isMonitoringActive = (userId) => {
    return userJobs.has(userId) || userIntervals.has(userId);
};

/**
 * Checks if a notification is pending for a specific user's URL
 *
 * @param {string} userId - ID of the user
 * @param {string} url - URL being monitored
 * @returns {boolean} - True if notification is pending, else false
 */
const isNotificationPending = (userId, url) => {
    if (!notificationTimers.has(userId)) return false;
    const userTimers = notificationTimers.get(userId);
    return Object.prototype.hasOwnProperty.call(userTimers, url);
};

/**
 * Sets a notification timer to prevent duplicate notifications
 *
 * @param {string} userId - ID of the user
 * @param {string} url - URL being monitored
 * @param {number} timeout - Duration to wait before allowing another notification (in ms)
 */
const setNotificationTimer = (userId, url, timeout) => {
    if (!notificationTimers.has(userId)) {
        notificationTimers.set(userId, {});
    }
    const userTimers = notificationTimers.get(userId);
    userTimers[url] = setTimeout(() => {
        // Timer expired, remove the pending notification
        if (notificationTimers.has(userId)) {
            delete userTimers[url];
            logger.info(`Notification timer expired for ${url} (User ID: ${userId})`);
            // If no more timers for the user, remove the user from the map
            if (Object.keys(userTimers).length === 0) {
                notificationTimers.delete(userId);
            }
        }
    }, timeout);
};

/**
 * Clears a notification timer when a URL recovers
 *
 * @param {string} userId - ID of the user
 * @param {string} url - URL being monitored
 */
const clearNotificationTimer = (userId, url) => {
    if (!notificationTimers.has(userId)) return;
    const userTimers = notificationTimers.get(userId);
    if (userTimers[url]) {
        clearTimeout(userTimers[url]);
        delete userTimers[url];
        logger.info(`Cleared notification timer for ${url} (User ID: ${userId})`);
        // If no more timers for the user, remove the user from the map
        if (Object.keys(userTimers).length === 0) {
            notificationTimers.delete(userId);
        }
    }
};

/**
 * Initializes monitoring for all existing verified users
 * Should be called once when the server starts
 */
const initializeMonitoring = async () => {
    try {
        const users = await User.find({ verified: true });
        users.forEach(user => {
            startMonitoring(user);
        });
        logger.info('Initialized monitoring for all existing verified users.');
    } catch (error) {
        logger.error('Error initializing monitoring:', error);
    }
};

/**
 * Stops all active monitoring (used during graceful shutdown)
 */
const stopAllMonitoring = () => {
    // Stop all cron jobs
    for (const [userId, job] of userJobs.entries()) {
        job.stop();
        logger.info(`Stopped cron job for user ID: ${userId}`);
    }
    userJobs.clear();

    // Stop all intervals
    for (const [userId, interval] of userIntervals.entries()) {
        clearInterval(interval);
        logger.info(`Stopped interval monitoring for user ID: ${userId}`);
    }
    userIntervals.clear();

    // Clear all notification timers
    for (const [userId, timers] of notificationTimers.entries()) {
        for (const url in timers) {
            clearTimeout(timers[url]);
            logger.info(`Cleared notification timer for ${url} (User ID: ${userId})`);
        }
    }
    notificationTimers.clear();

    // Clear all locks
    userLocks.clear();

    logger.info('All monitoring and notification timers have been stopped.');
};

/**
 * Gracefully stops all monitoring and cleans up resources
 * Should be called during server shutdown
 */
const gracefulShutdown = () => {
    logger.info('Initiating graceful shutdown...');
    stopAllMonitoring();
    // Additional shutdown tasks can be added here
    // e.g., closing database connections, flushing logs, etc.
};

module.exports = {
    startMonitoring,
    stopMonitoring,
    restartMonitoring,
    initializeMonitoring,
    isMonitoringActive,
    stopAllMonitoring,
    gracefulShutdown, // Exported for server shutdown handling
};
""""
"""
// services/screenshotService.js

const puppeteer = require('puppeteer');
const cloudinary = require('../config/cloudinary');
const sharp = require('sharp');
const logger = require('../utils/logger');
const streamifier = require('streamifier');

// Initialize Puppeteer browser instance
let browserInstance = null;

const initBrowser = async () => {
  if (!browserInstance) {
    browserInstance = await puppeteer.launch({ args: ['--no-sandbox'] });
    logger.info('Puppeteer browser launched');
  }
  return browserInstance;
};

// Function to take a screenshot, compress, upload to Cloudinary, and return the URL
const takeScreenshot = async (url) => {
  try {
    const browser = await initBrowser();
    const page = await browser.newPage();

    // Set a reasonable viewport size
    await page.setViewport({ width: 1280, height: 800 });

    // Navigate to the URL
    await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 }); // 30 seconds timeout

    // Capture the screenshot as a buffer
    const screenshotBuffer = await page.screenshot({ fullPage: true });

    await page.close();

    logger.info(`Screenshot captured for ${url}`);

    // Compress the image using Sharp
    const compressedBuffer = await sharp(screenshotBuffer)
      .jpeg({ quality: 20 }) // Adjust quality as needed (30 for high compression)
      .toBuffer();

    logger.info(`Screenshot compressed for ${url}`);

    // Generate a unique filename
    const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
    const sanitizedUrl = url.replace(/[^a-zA-Z0-9]/g, '_');
    const filename = `${sanitizedUrl}_${timestamp}`; // Removed extension

    // Upload the compressed image to Cloudinary using a single upload_stream
    const uploadPromise = new Promise((resolve, reject) => {
      const stream = cloudinary.uploader.upload_stream(
        {
          folder: 'screenshots', // Optional: specify a folder in Cloudinary
          public_id: filename,
          resource_type: 'image',
          format: 'jpg', // Specify the format to ensure consistent extension
        },
        (error, result) => {
          if (error) {
            logger.error(`Cloudinary upload error for ${url}: ${error.message}`);
            return reject(error);
          } else {
            logger.info(`Screenshot uploaded to Cloudinary: ${result.secure_url}`);
            return resolve(result.secure_url);
          }
        }
      );
      streamifier.createReadStream(compressedBuffer).pipe(stream);
    });

    const cloudinaryUrl = await uploadPromise;

    return cloudinaryUrl; // Return the Cloudinary URL
  } catch (error) {
    logger.error(`Error taking screenshot for ${url}: ${error.message}`);
    throw error;
  }
};

module.exports = {
  takeScreenshot,
};
"""
make hte screenshot more intelligent many things seems regarding everytiign seems redudnant and wastefull