now can you make it so that the monotoring service is only possible after user is verified and throws a error if trued in a nyway to startmonotor in anyendpoint i dont know how to verify email to start monitoing 
""""
const { z } = require('zod');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const User = require('../models/User');
const monitorService = require('../services/monitorService');
const logger = require('../utils/logger');
const crypto = require('crypto');
const { sendVerificationEmail } = require('../services/emailService');

// Zod Schemas
const urlSchema = z.string().url().trim();
const timePeriodSchema = z.enum(['30s', '1m', '3m', '5m', '10m', '1h']);

const signupSchema = z.object({
    username: z.string().min(3).max(30).trim(),
    email: z.string().email().toLowerCase().trim(),
    password: z.string().min(8)
        .regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/,
            'Password must contain at least one uppercase letter, one lowercase letter, one number and one special character'),
    listOfUrls: z.array(urlSchema).default([]),
    timePeriod: timePeriodSchema.default('1m'),
    emailSend: z.boolean().default(false),
});

const loginSchema = z.object({
    identifier: z.string().min(3).trim(),
    password: z.string().min(8),
});

const verifyEmailSchema = z.object({
    token: z.string().min(32),
});


exports.signup = async (req, res) => {
    try {
        // Parse and validate user input
        const parsedData = signupSchema.parse(req.body);
        const { username, email, password, listOfUrls, timePeriod, emailSend } = parsedData;

        // Check if user already exists
        const existingUser = await User.findOne({
            $or: [{ username }, { email }]
        });

        if (existingUser) {
            return res.status(409).json({
                message: 'Account already exists',
                field: existingUser.email === email ? 'email' : 'username'
            });
        }

        // Hash the password
        const hashedPassword = await bcrypt.hash(password, 12);
        const verificationToken = crypto.randomBytes(32).toString('hex');

        // Create a new user
        const user = new User({
            username,
            email,
            password: hashedPassword,
            listOfUrls,
            timePeriod,
            emailSend,
            verificationToken,
            verified: false,
        });

        await user.save();

        // Start monitoring service
        await monitorService.startMonitoring(user);

        // Send verification email
        await sendVerificationEmail(email, verificationToken);

        // Generate JWT
        const token = jwt.sign(
            {
                id: user._id,
                username: user.username,
                email: user.email
            },
            process.env.JWT_SECRET,
            { expiresIn: '24h' }
        );

        res.status(201).json({
            message: 'Registration successful. Please verify your email.',
            token,
            user: {
                id: user._id,
                username: user.username,
                email: user.email,
                verified: false,
            }
        });
    } catch (error) {
        if (error instanceof z.ZodError) {
            return res.status(400).json({
                message: 'Validation failed',
                errors: error.errors.map(err => ({
                    field: err.path.join('.'),
                    message: err.message
                }))
            });
        }
        logger.error('Signup Error:', error);
        res.status(500).json({ message: 'Internal server error' });
    }
};

exports.login = async (req, res) => {
    try {
        const parsedData = loginSchema.parse(req.body);
        const { identifier, password } = parsedData;

        // Find user by email or username
        const user = await User.findOne({
            $or: [
                { email: identifier.toLowerCase() },
                { username: identifier }
            ]
        });

        if (!user) {
            return res.status(401).json({ message: 'Invalid credentials' });
        }

        // Verify password
        const isValidPassword = await bcrypt.compare(password, user.password);
        if (!isValidPassword) {
            return res.status(401).json({ message: 'Invalid credentials' });
        }

        // Generate JWT
        const token = jwt.sign(
            { 
                id: user._id,
                username: user.username,
                email: user.email 
            },
            process.env.JWT_SECRET,
            { expiresIn: '24h' }
        );

        res.status(200).json({
            message: 'Login successful',
            token,
            user: {
                id: user._id,
                username: user.username,
                email: user.email,
                verified: user.verified
            }
        });
    } catch (error) {
        if (error instanceof z.ZodError) {
            return res.status(400).json({
                message: 'Validation failed',
                errors: error.errors.map(err => ({
                    field: err.path.join('.'),
                    message: err.message
                }))
            });
        }
        logger.error('Login Error:', error);
        res.status(500).json({ message: 'Internal server error' });
    }
};

exports.verifyEmail = async (req, res) => {
    try {
        const { token } = verifyEmailSchema.parse(req.body);

        const user = await User.findOne({ 
            verificationToken: token,
            verified: false
        });

        if (!user) {
            return res.status(400).json({ message: 'Invalid or expired verification token' });
        }

        user.verified = true;
        user.verificationToken = undefined;
        await user.save();

        res.status(200).json({ message: 'Email verified successfully' });
    } catch (error) {
        if (error instanceof z.ZodError) {
            return res.status(400).json({
                message: 'Validation failed',
                errors: error.errors.map(err => ({
                    field: err.path.join('.'),
                    message: err.message
                }))
            });
        }
        logger.error('Email Verification Error:', error);
        res.status(500).json({ message: 'Internal server error' });
    }
};

exports.checkVerificationStatus = async (req, res) => {
    try {
        const userId = z.string().min(1).parse(req.params.userId);

        const user = await User.findById(userId).select('verified email');
        if (!user) {
            return res.status(404).json({ message: 'User not found' });
        }

        res.status(200).json({
            verified: user.verified,
            email: user.email
        });
    } catch (error) {
        if (error instanceof z.ZodError) {
            return res.status(400).json({ message: 'Invalid user ID' });
        }
        logger.error('Check Verification Status Error:', error);
        res.status(500).json({ message: 'Internal server error' });
    }
};
"""
"""
const { z } = require('zod');
const User = require('../models/User');
const Log = require('../models/Log');
const monitorService = require('../services/monitorService');
const logger = require('../utils/logger');

// Zod Schemas
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(),
});

const getLogsQuerySchema = z.object({
    page: z.string(),
    limit: z.string(),
});

exports.updateSettings = async (req, res) => {
    try {
        // Validate input
        const parsedData = updateSettingsSchema.parse(req.body);

        // Update user
        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' });

        // Restart monitoring with updated settings
        monitorService.restartMonitoring(updatedUser);

        res.status(200).json({ message: 'Settings updated successfully', user: updatedUser });
    } catch (error) {
        if (error instanceof z.ZodError) {
            return res.status(400).json({ errors: error.errors });
        }
        // Handle duplicate key error (e.g., email or username already exists)
        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` });
        }
        logger.error('Update Settings Error:', error);
        res.status(500).json({ message: 'Server Error' });
    }
};

exports.getUserLogs = async (req, res) => {
    try {
        // Validate query parameters
        const parsedQuery = getLogsQuerySchema.parse(req.query);
        const page = parseInt(parsedQuery.page) || 1;
        const limit = parseInt(parsedQuery.limit) || 20;
        const skip = (page - 1) * limit;

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

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

        res.status(200).json({
            totalPages: Math.ceil(totalLogs / limit),
            currentPage: page,
            logs,
        });
    } catch (error) {
        if (error instanceof z.ZodError) {
            return res.status(400).json({ errors: error.errors });
        }
        logger.error('Get User Logs Error:', error);
        res.status(500).json({ message: 'Server Error' });
    }
};
"""
"""
const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({
    username: { type: String, unique: true, sparse: true, minlength: 3, maxlength: 30 },
    email: { type: String, unique: true, sparse: true, maxlength: 100 },
    password: { type: String, required: true, minlength: 6 },
    listOfUrls: { type: [String], default: [] },
    timePeriod: { 
        type: String, 
        enum: ['30s', '1m', '3m', '5m', '10m', '1h'], 
        default: '1m' 
    },
    emailSend: { type: Boolean, default: false },
    verificationToken: { type: String },
    verified: { type: Boolean, default: false },
}, { timestamps: true });

// Adding indexes for sparse unique fields
userSchema.index({ username: 1 }, { unique: true, sparse: true });
userSchema.index({ email: 1 }, { unique: true, sparse: true });

module.exports = mongoose.model('User', userSchema);
"""
"""
// routes/authRoutes.js

const express = require('express');
const router = express.Router();
const authController = require('../controllers/authController');

// Existing routes
router.post('/signup', authController.signup);
router.post('/login', authController.login);

// New verification routes
router.post('/verify-email', authController.verifyEmail);
router.get('/check-verification/:userId', authController.checkVerificationStatus);

module.exports = router;
"""
"""
// routes/userRoutes.js

const express = require('express');
const router = express.Router();
const userController = require('../controllers/userController');
const authenticate = require('../middlewares/authenticate');

router.put('/settings', authenticate, userController.updateSettings);
router.get('/logs', authenticate, userController.getUserLogs);

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-email?token=${token}`;

    const mailOptions = {
        from: process.env.EMAIL_USER,
        to: email,
        subject: 'Email Verification',
        html: `
            <p>Thank you for registering. Please verify your email by clicking the link below:</p>
            <a href="${verificationLink}">
                <button style="padding: 10px 20px; background-color: #28a745; color: white; border: none; border-radius: 5px;">
                    Verify Email
                </button>
            </a>
            <p>If you did not register, please ignore this email.</p>
        `,
    };

    try {
        await transporter.sendMail(mailOptions);
        logger.info(`Verification email sent to ${email}`);
    } catch (error) {
        logger.error(`Error sending verification email to ${email}:`, error);
        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 screenshotService = require('./screenshotService');
const emailService = require('./emailService');
const logger = require('../utils/logger');

// Helper: Convert time period to cron expression
const timePeriodToCron = (timePeriod) => {
    switch (timePeriod) {
        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 cron jobs and intervals
const userJobs = new Map();
const userIntervals = new Map();

// In-memory storage for notification timers
// Structure: { userId: { url: timeoutObject } }
const notificationTimers = new Map();

/**
 * Function to perform checks on user's URLs.
 * Logs all status codes, handles notifications for non-2xx responses,
 * and captures screenshots for error notifications.
 *
 * @param {Object} user - The user object containing monitoring details.
 */
const performChecks = async (user) => {
    for (const url of user.listOfUrls) {
        try {
            const response = await axios.get(url, { timeout: 10000 });
            const statusCode = response.status;

            // Log successful check with no screenshot
            await logStatus(user._id, url, statusCode, "None");

            if (statusCode < 200 || statusCode >= 300) {
                logger.warn(`URL check failed for ${url} with status code ${statusCode}`);

                if (isNotificationPending(user._id.toString(), url)) {
                    logger.info(`Notification already pending for ${url}. Skipping email.`);
                    continue;
                }

                const screenshotUrl = await screenshotService.takeScreenshot(url);
                await emailService.sendErrorNotification(user.email, url, statusCode, screenshotUrl);
                await logStatus(user._id, url, statusCode, screenshotUrl); // Log with screenshot URL

                setNotificationTimer(user._id.toString(), url, 5 * 60 * 1000); // 5 minutes
            } else {
                logger.info(`URL check successful for ${url} with status code ${statusCode}`);
                clearNotificationTimer(user._id.toString(), url);
            }
        } catch (error) {
            let statusCode = error.response ? error.response.status : 0;
            let screenshotUrl = 'None';

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

            await logStatus(user._id, url, statusCode, screenshotUrl); // Log with or without screenshot
            if (!isNotificationPending(user._id.toString(), url)) {
                await emailService.sendErrorNotification(user.email, url, statusCode, screenshotUrl);
                setNotificationTimer(user._id.toString(), url, 5 * 60 * 1000);
            }
        }
    }
};

/**
 * Logs the status of the URL check to the database.
 *
 * @param {ObjectId} userId - The ID of the user.
 * @param {string} url - The URL that was checked.
 * @param {number} statusCode - The HTTP status code returned.
 */
const logStatus = async (userId, url, statusCode, screenshotUrl) => {
    try {
        const log = new Log({
            user: userId,
            url,
            statusCode,
            screenshotUrl,
            timestamp: new Date(),
        });
        await log.save();
        logger.info(`Logged status for ${url} with status code ${statusCode} and screenshot URL: ${screenshotUrl}`);
    } catch (logError) {
        logger.error(`Failed to log status for ${url}: ${logError.message}`);
    }
};

// Function to start monitoring for a user
const startMonitoring = (user) => {
    if (!user.listOfUrls || user.listOfUrls.length === 0) return;

    // Clear existing jobs or intervals to prevent duplicates
    stopMonitoring(user);

    if (user.timePeriod === '30s') {
        // node-cron doesn't support seconds intervals, use setInterval
        const interval = setInterval(() => {
            performChecks(user);
        }, 30000); // 30 seconds

        userIntervals.set(user._id.toString(), interval);
        logger.info(`Started 30s interval monitoring for user ${user.username}`);
    } else {
        const cronExpression = timePeriodToCron(user.timePeriod);
        if (!cronExpression) return;

        const job = cron.schedule(cronExpression, () => {
            performChecks(user);
        }, {
            scheduled: true,
            timezone: "UTC",
        });

        userJobs.set(user._id.toString(), job);
        logger.info(`Started cron job (${cronExpression}) monitoring for user ${user.username}`);
    }
};

// Function to stop monitoring for a user
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}`);
    }

    // Also clear any pending notification timers
    if (notificationTimers.has(userId)) {
        Object.values(notificationTimers.get(userId)).forEach(timeout => clearTimeout(timeout));
        notificationTimers.delete(userId);
        logger.info(`Cleared notification timers for user ${user.username}`);
    }
};

// Function to restart monitoring (used when settings are updated)
const restartMonitoring = (user) => {
    startMonitoring(user);
};

// Function to check if a notification is pending for a URL
const isNotificationPending = (userId, url) => {
    if (!notificationTimers.has(userId)) return false;
    const userTimers = notificationTimers.get(userId);
    return userTimers.hasOwnProperty(url);
};

// Function to set a notification timer for a URL
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 notificationTimers.get(userId)[url];
            logger.info(`Notification timer expired for ${url}`);
            // Optionally, notify the user that monitoring is active again
            // Example:
            // emailService.sendRecoveryNotification(user.email, url);
        }
    }, timeout);
};

// Function to clear notification timer (called when URL recovers)
const clearNotificationTimer = (userId, url) => {
    if (!notificationTimers.has(userId)) return;
    const userTimers = notificationTimers.get(userId);
    if (userTimers.hasOwnProperty(url)) {
        clearTimeout(userTimers[url]);
        delete userTimers[url];
        logger.info(`Cleared notification timer for ${url}`);
    }
};

// Initialize monitoring for existing users on server start
const initializeMonitoring = async () => {
    const User = require('../models/User'); // Avoid circular dependency
    try {
        const users = await User.find();
        users.forEach(user => {
            startMonitoring(user);
        });
        logger.info('Initialized monitoring for existing users');
    } catch (error) {
        logger.error('Error initializing monitoring:', error);
    }
};

module.exports = {
    startMonitoring,
    restartMonitoring,
    initializeMonitoring,
};
"""
"""
// 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: 30 }) // 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,
};
"""
"""
// server.js

const express = require('express');
const dotenv = require('dotenv');
const helmet = require('helmet');
const cors = require('cors');
const rateLimit = require('express-rate-limit');
const path = require('path');
const connectDB = require('./config/db');
const errorHandler = require('./middlewares/errorHandler');
const authRoutes = require('./routes/authRoutes');
const userRoutes = require('./routes/userRoutes');
const monitorService = require('./services/monitorService');
const logger = require('./utils/logger');

// Load environment variables
dotenv.config();

// Initialize Express
const app = express();

// Connect to MongoDB
connectDB();

// Middleware
app.use(express.json());
app.use(helmet());
app.use(cors({
    origin: ['http://localhost:3000'], // Replace with your frontend domain
    methods: ['GET', 'POST', 'PUT', 'DELETE'],
    credentials: true,
}));

// Rate Limiting
const authLimiter = rateLimit({
    windowMs: 15 * 60 * 1000, // 15 minutes
    max: 100, // limit each IP to 100 requests per windowMs
    message: 'Too many requests from this IP, please try again after 15 minutes',
});

app.use('/api/auth/signup', authLimiter);
app.use('/api/auth/login', authLimiter);
app.use('/api/user/settings', authLimiter);
app.use('/api/user/logs', authLimiter);

// Serve static screenshots
app.use('/screenshots', express.static(path.join(__dirname, 'screenshots')));

// Routes
app.use('/api/auth', authRoutes);
app.use('/api/user', userRoutes);

// Global Error Handler
app.use(errorHandler);

// Start Monitoring for Existing Users
monitorService.initializeMonitoring();

// Start Server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
    logger.info(`Server is running on port ${PORT}`);
});