const Admin = require('../models/adminModel'); const User = require('../models/userModel'); const ProductModel = require('../models/productModel'); const asyncHandler = require('express-async-handler'); const jwt = require('jsonwebtoken'); const bcrypt = require('bcryptjs'); const multer = require('multer'); const path = require('path'); const fs = require('fs'); const { getNextImageNumber, isValidImageFile } = require('../utils/imageNumbering'); const generateAdminToken = (res, adminId) => { const token = jwt.sign({ id: adminId }, process.env.JWT_SECRET_KEY, { expiresIn: '24h', }); const isProduction = process.env.NODE_ENV === 'production'; res.cookie('adminToken', token, { httpOnly: true, secure: isProduction, sameSite: isProduction ? 'none' : 'lax', maxAge: 24 * 60 * 60 * 1000, ...(isProduction && process.env.COOKIE_DOMAIN && { domain: process.env.COOKIE_DOMAIN }) }); return token; }; const adminLogin = asyncHandler(async (req, res) => { const { username, password } = req.body; if (!username || !password) { res.status(400); throw new Error('Please provide username and password'); } const admin = await Admin.findOne({ $or: [{ username }, { email: username }] }); if (!admin) { res.status(401); throw new Error('Invalid credentials'); } if (!admin.isActive) { res.status(401); throw new Error('Account is deactivated'); } const isPasswordValid = await admin.checkPassword(password); if (!isPasswordValid) { res.status(401); throw new Error('Invalid credentials'); } await Admin.findByIdAndUpdate(admin._id, { lastLogin: new Date() }); const token = generateAdminToken(res, admin._id); res.status(200).json({ _id: admin._id, username: admin.username, email: admin.email, firstName: admin.firstName, lastName: admin.lastName, role: admin.role, permissions: admin.permissions, avatar: admin.avatar, token }); }); const adminLogout = asyncHandler(async (req, res) => { const isProduction = process.env.NODE_ENV === 'production'; res.cookie('adminToken', '', { httpOnly: true, expires: new Date(0), secure: isProduction, sameSite: isProduction ? 'none' : 'lax', ...(isProduction && process.env.COOKIE_DOMAIN && { domain: process.env.COOKIE_DOMAIN }) }); res.status(200).json({ message: 'Logged out successfully' }); }); const getAdminProfile = asyncHandler(async (req, res) => { const admin = await Admin.findById(req.admin._id).select('-password'); res.status(200).json(admin); }); const updateAdminProfile = asyncHandler(async (req, res) => { const { firstName, lastName, email, avatar, preferences } = req.body; const admin = await Admin.findById(req.admin._id); if (admin) { admin.firstName = firstName || admin.firstName; admin.lastName = lastName || admin.lastName; admin.email = email || admin.email; admin.avatar = avatar || admin.avatar; admin.preferences = { ...admin.preferences, ...preferences }; const updatedAdmin = await admin.save(); res.status(200).json({ _id: updatedAdmin._id, username: updatedAdmin.username, email: updatedAdmin.email, firstName: updatedAdmin.firstName, lastName: updatedAdmin.lastName, role: updatedAdmin.role, permissions: updatedAdmin.permissions, avatar: updatedAdmin.avatar, preferences: updatedAdmin.preferences }); } else { res.status(404); throw new Error('Admin not found'); } }); const getAllUsers = asyncHandler(async (req, res) => { const page = parseInt(req.query.page) || 1; const limit = parseInt(req.query.limit) || 10; const search = req.query.search || ''; const filter = req.query.filter || 'all'; const skip = (page - 1) * limit; const andConditions = []; if (search) { andConditions.push({ $or: [ { name: { $regex: search, $options: 'i' } }, { email: { $regex: search, $options: 'i' } } ] }); } if (filter === 'active') { andConditions.push({ $or: [ { isActive: true }, { isActive: { $exists: false } } ] }); } else if (filter === 'inactive') { andConditions.push({ isActive: false }); } const query = andConditions.length > 0 ? { $and: andConditions } : {}; const users = await User.find(query) .select('-password') .sort({ createdAt: -1 }) .skip(skip) .limit(limit); const usersWithDetails = users.map(user => { let recentAddress = '', recentCity = '', recentPhone = ''; if (user.orders && user.orders.length > 0) { const latestOrder = user.orders.reduce((latest, curr) => { return (!latest || (curr.createdAt > latest.createdAt)) ? curr : latest; }, null); if (latestOrder && latestOrder.shippingAddress) { recentAddress = latestOrder.shippingAddress.address || latestOrder.shippingAddress.fullName || ''; recentCity = latestOrder.shippingAddress.city || ''; recentPhone = latestOrder.shippingAddress.phone || ''; } } return { _id: user._id, name: user.name, email: user.email, isActive: typeof user.isActive === 'boolean' ? user.isActive : true, createdAt: user.createdAt, recentAddress, recentCity, recentPhone, country: user.country || '', gender: user.gender || '', dateOfBirth: user.dateOfBirth || '' }; }); const total = await User.countDocuments(query); res.status(200).json({ users: usersWithDetails, pagination: { page, limit, total, pages: Math.ceil(total / limit) } }); }); const getUserById = asyncHandler(async (req, res) => { const user = await User.findById(req.params.id).select('-password'); let recentAddress = '', recentCity = '', recentPhone = ''; if (user && user.orders && user.orders.length > 0) { const latestOrder = user.orders.reduce((latest, curr) => { return (!latest || (curr.createdAt > latest.createdAt)) ? curr : latest; }, null); if (latestOrder && latestOrder.shippingAddress) { recentAddress = latestOrder.shippingAddress.address || latestOrder.shippingAddress.fullName || ''; recentCity = latestOrder.shippingAddress.city || ''; recentPhone = latestOrder.shippingAddress.phone || ''; } } if (user) { res.status(200).json({ _id: user._id, name: user.name, email: user.email, isActive: typeof user.isActive === 'boolean' ? user.isActive : true, createdAt: user.createdAt, recentAddress, recentCity, recentPhone, country: user.country || '', gender: user.gender || '', dateOfBirth: user.dateOfBirth || '' }); } else { res.status(404); throw new Error('User not found'); } }); const updateUser = asyncHandler(async (req, res) => { const { name, email, isActive } = req.body; const user = await User.findById(req.params.id); if (user) { user.name = name || user.name; user.email = email || user.email; if (typeof isActive === 'boolean') { user.isActive = isActive; } const updatedUser = await user.save(); res.status(200).json({ _id: updatedUser._id, name: updatedUser.name, email: updatedUser.email, isActive: updatedUser.isActive }); } else { res.status(404); throw new Error('User not found'); } }); const deleteUser = asyncHandler(async (req, res) => { const user = await User.findById(req.params.id); if (user) { await User.findByIdAndDelete(req.params.id); res.status(200).json({ message: 'User deleted successfully' }); } else { res.status(404); throw new Error('User not found'); } }); const createUser = asyncHandler(async (req, res) => { const { name, email, password, isActive = true } = req.body; if (!name || !email || !password) { res.status(400); throw new Error('Please provide name, email, and password'); } const existingUser = await User.findOne({ email }); if (existingUser) { res.status(400); throw new Error('User with this email already exists'); } const user = await User.create({ name, email, password, isActive, createdAt: new Date(), }); res.status(201).json({ _id: user._id, name: user.name, email: user.email, isActive: user.isActive, createdAt: user.createdAt }); }); const getAllProducts = asyncHandler(async (req, res) => { const page = parseInt(req.query.page) || 1; const limit = parseInt(req.query.limit) || 10; const search = req.query.search || ''; const category = req.query.category || ''; const sortBy = req.query.sortBy || 'createdAt'; const sortOrder = req.query.sortOrder || 'desc'; const skip = (page - 1) * limit; let query = {}; if (search) { query.name = { $regex: search, $options: 'i' }; } if (category) { query.category = category; } const sortOptions = {}; sortOptions[sortBy] = sortOrder === 'desc' ? -1 : 1; const products = await ProductModel.find(query) .sort(sortOptions) .skip(skip) .limit(limit); const total = await ProductModel.countDocuments(query); res.status(200).json({ products, pagination: { page, limit, total, pages: Math.ceil(total / limit) } }); }); const createProduct = asyncHandler(async (req, res) => { const { name, price, description, category, seller, stock, images, specifications, warrantyDetails, afterSalesSupport, ratings, numOfReviews, PremiumBadge, reviews } = req.body; if (!name || !price || !category) { res.status(400); throw new Error('Please provide name, price, and category'); } await ensureCategoryExists(category); console.log('Creating product with images:', images); const product = await ProductModel.create({ name, price, description, category, seller, stock: stock || 0, images: images || [], specifications, warrantyDetails, afterSalesSupport, ratings: ratings , numOfReviews: numOfReviews || 0, PremiumBadge, reviews: reviews || [] }); console.log('Product created successfully:', product._id); res.status(201).json(product); }); const updateProduct = asyncHandler(async (req, res) => { const { name, price, description, category, seller, stock, images, specifications, warrantyDetails, afterSalesSupport, ratings, numOfReviews, PremiumBadge, reviews } = req.body; const product = await ProductModel.findById(req.params.id); if (product) { console.log('Updating product with images:', images); if (category && category !== product.category) { await ensureCategoryExists(category); } product.name = name || product.name; product.price = price || product.price; product.description = description || product.description; product.category = category || product.category; product.seller = seller || product.seller; product.stock = stock !== undefined ? stock : product.stock; product.images = images || product.images; product.specifications = specifications || product.specifications; product.warrantyDetails = warrantyDetails || product.warrantyDetails; product.afterSalesSupport = afterSalesSupport || product.afterSalesSupport; product.ratings = ratings ||product.ratings; product.numOfReviews = numOfReviews !== undefined ? numOfReviews : product.numOfReviews; product.PremiumBadge = PremiumBadge !== undefined ? PremiumBadge : product.PremiumBadge; product.reviews = reviews || product.reviews; const updatedProduct = await product.save(); console.log('Product updated successfully:', updatedProduct._id); res.status(200).json(updatedProduct); } else { res.status(404); throw new Error('Product not found'); } }); const deleteProduct = asyncHandler(async (req, res) => { const product = await ProductModel.findById(req.params.id); if (product) { await ProductModel.findByIdAndDelete(req.params.id); res.status(200).json({ message: 'Product deleted successfully' }); } else { res.status(404); throw new Error('Product not found'); } }); const uploadProductImages = asyncHandler(async (req, res) => { try { console.log('Upload request received:', req.files); if (!req.files || req.files.length === 0) { res.status(400); throw new Error('No files uploaded'); } const uploadedImages = req.files.map(file => { const imagePath = `/images/products/${file.filename}`; console.log('Storing image path in database:', imagePath); return { image: imagePath }; }); console.log('Uploaded images:', uploadedImages); res.status(200).json({ success: true, images: uploadedImages, message: `${uploadedImages.length} image(s) uploaded successfully` }); } catch (error) { console.error('Upload error:', error); res.status(500).json({ success: false, message: 'Error uploading images', error: error.message }); } }); const getDashboardStats = asyncHandler(async (req, res) => { const today = new Date(); const startOfDay = new Date(today.setHours(0, 0, 0, 0)); const startOfWeek = new Date(today.setDate(today.getDate() - today.getDay())); const startOfMonth = new Date(today.getFullYear(), today.getMonth(), 1); const startOfYear = new Date(today.getFullYear(), 0, 1); const [ totalUsers, activeUsers, newUsersToday, newUsersThisWeek, newUsersThisMonth, newUsersThisYear, totalProducts, lowStockProducts, outOfStockProducts, highRatedProducts, topProducts ] = await Promise.all([ User.countDocuments(), User.countDocuments({ $or: [{ isActive: true }, { isActive: { $exists: false } }] }), User.countDocuments({ createdAt: { $gte: startOfDay } }), User.countDocuments({ createdAt: { $gte: startOfWeek } }), User.countDocuments({ createdAt: { $gte: startOfMonth } }), User.countDocuments({ createdAt: { $gte: startOfYear } }), ProductModel.countDocuments(), ProductModel.countDocuments({ stock: { $lt: 10, $gt: 0 } }), ProductModel.countDocuments({ stock: 0 }), ProductModel.countDocuments({ ratings: { $gte: 4 } }), ProductModel.aggregate([ { $sort: { ratings: -1, numOfReviews: -1 } }, { $limit: 8 }, { $project: { name: 1, price: 1, ratings: 1, numOfReviews: 1, stock: 1, category: 1, images: 1 } } ]) ]); const orderStats = await User.aggregate([ { $unwind: '$orders' }, { $group: { _id: null, totalOrders: { $sum: 1 }, totalRevenue: { $sum: '$orders.amount' }, todayOrders: { $sum: { $cond: [ { $gte: ['$orders.createdAt', startOfDay] }, 1, 0 ] } }, todayRevenue: { $sum: { $cond: [ { $gte: ['$orders.createdAt', startOfDay] }, '$orders.amount', 0 ] } }, weekOrders: { $sum: { $cond: [ { $gte: ['$orders.createdAt', startOfWeek] }, 1, 0 ] } }, weekRevenue: { $sum: { $cond: [ { $gte: ['$orders.createdAt', startOfWeek] }, '$orders.amount', 0 ] } }, monthOrders: { $sum: { $cond: [ { $gte: ['$orders.createdAt', startOfMonth] }, 1, 0 ] } }, monthRevenue: { $sum: { $cond: [ { $gte: ['$orders.createdAt', startOfMonth] }, '$orders.amount', 0 ] } }, pendingOrders: { $sum: { $cond: [ { $eq: [{ $toLower: '$orders.status' }, 'placed'] }, 1, 0 ] } }, processingOrders: { $sum: { $cond: [ { $eq: [{ $toLower: '$orders.status' }, 'processing'] }, 1, 0 ] } }, shippedOrders: { $sum: { $cond: [ { $eq: [{ $toLower: '$orders.status' }, 'shipped'] }, 1, 0 ] } }, deliveredOrders: { $sum: { $cond: [ { $eq: [{ $toLower: '$orders.status' }, 'delivered'] }, 1, 0 ] } } } } ]); const stats = orderStats[0] || { totalOrders: 0, totalRevenue: 0, todayOrders: 0, todayRevenue: 0, weekOrders: 0, weekRevenue: 0, monthOrders: 0, monthRevenue: 0, pendingOrders: 0, processingOrders: 0, shippedOrders: 0, deliveredOrders: 0 }; const recentOrders = await User.aggregate([ { $unwind: '$orders' }, { $sort: { 'orders.createdAt': -1 } }, { $limit: 10 }, { $project: { orderId: '$orders._id', userId: '$_id', userName: '$name', userEmail: '$email', amount: '$orders.amount', status: '$orders.status', createdAt: '$orders.createdAt', items: '$orders.orderItems' } } ]); const salesTrends = await User.aggregate([ { $unwind: '$orders' }, { $match: { 'orders.createdAt': { $gte: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) } } }, { $group: { _id: { $dateToString: { format: '%Y-%m-%d', date: '$orders.createdAt' } }, orders: { $sum: 1 }, revenue: { $sum: '$orders.amount' } } }, { $sort: { _id: 1 } } ]); const categoryStats = await ProductModel.aggregate([ { $group: { _id: '$category', count: { $sum: 1 } } }, { $sort: { count: -1 } } ]); res.status(200).json({ users: { total: totalUsers, active: activeUsers, newToday: newUsersToday, newThisWeek: newUsersThisWeek, newThisMonth: newUsersThisMonth, newThisYear: newUsersThisYear, growthRate: totalUsers > 0 ? ((newUsersThisMonth / totalUsers) * 100).toFixed(2) : 0 }, products: { total: totalProducts, lowStock: lowStockProducts, outOfStock: outOfStockProducts, highRated: highRatedProducts, categories: categoryStats }, orders: { total: stats.totalOrders, totalRevenue: stats.totalRevenue, todayOrders: stats.todayOrders, todayRevenue: stats.todayRevenue, weekOrders: stats.weekOrders, weekRevenue: stats.weekRevenue, monthOrders: stats.monthOrders, monthRevenue: stats.monthRevenue, statusBreakdown: { pending: stats.pendingOrders, processing: stats.processingOrders, shipped: stats.shippedOrders, delivered: stats.deliveredOrders }, averageOrderValue: stats.totalOrders > 0 ? (stats.totalRevenue / stats.totalOrders).toFixed(2) : 0 }, topProducts, latestOrders: recentOrders, salesTrends, systemHealth: { database: 'healthy', uptime: process.uptime(), memory: process.memoryUsage(), timestamp: new Date().toISOString() } }); }); const getAllOrders = asyncHandler(async (req, res) => { const page = parseInt(req.query.page) || 1; const limit = parseInt(req.query.limit) || 10; const status = req.query.status || 'all'; const period = req.query.period || '30d'; const skip = (page - 1) * limit; let startDate; const endDate = new Date(); switch (period) { case '7d': startDate = new Date(endDate.getTime() - 7 * 24 * 60 * 60 * 1000); break; case '30d': startDate = new Date(endDate.getTime() - 30 * 24 * 60 * 60 * 1000); break; case '90d': startDate = new Date(endDate.getTime() - 90 * 24 * 60 * 60 * 1000); break; default: startDate = new Date(endDate.getTime() - 30 * 24 * 60 * 60 * 1000); } const users = await User.find({ 'orders.createdAt': { $gte: startDate, $lte: endDate } }); let allOrders = []; users.forEach(user => { user.orders.forEach(order => { if (order.createdAt >= startDate && order.createdAt <= endDate) { allOrders.push({ _id: order._id, orderId: order._id, userId: user._id, userName: user.name, userEmail: user.email, amount: order.amount, status: order.status, createdAt: order.createdAt, items: order.orderItems || [], shippingAddress: order.shippingAddress, paymentMethod: order.paymentMethod, estimatedDelivery: order.estimatedDelivery, phone: order.shippingAddress?.phone || '', city: order.shippingAddress?.city || '' }); } }); }); if (status !== 'all') { allOrders = allOrders.filter(order => order.status === status); } allOrders.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt)); const total = allOrders.length; const orders = allOrders.slice(skip, skip + limit); res.status(200).json({ orders, pagination: { page, limit, total, pages: Math.ceil(total / limit) } }); }); const getOrderById = asyncHandler(async (req, res) => { const { id } = req.params; const user = await User.findOne({ 'orders._id': id }); if (!user) { res.status(404); throw new Error('Order not found'); } const order = user.orders.find(order => order._id.toString() === id); if (order) { res.status(200).json({ order: { ...order.toObject(), userName: user.name, userEmail: user.email, shippingAddress: order.shippingAddress, paymentMethod: order.paymentMethod, estimatedDelivery: order.estimatedDelivery, phone: order.shippingAddress?.phone || '', city: order.shippingAddress?.city || '' } }); } else { res.status(404); throw new Error('Order not found'); } }); const updateOrder = asyncHandler(async (req, res) => { const { id } = req.params; const { status } = req.body; const user = await User.findOne({ 'orders._id': id }); if (!user) { res.status(404); throw new Error('Order not found'); } const orderIndex = user.orders.findIndex(order => order._id.toString() === id); if (orderIndex === -1) { res.status(404); throw new Error('Order not found'); } user.orders[orderIndex].status = status; await user.save(); res.status(200).json({ message: 'Order updated successfully', order: user.orders[orderIndex] }); }); const deleteOrder = asyncHandler(async (req, res) => { const { id } = req.params; const user = await User.findOne({ 'orders._id': id }); if (!user) { res.status(404); throw new Error('Order not found'); } user.orders = user.orders.filter(order => order._id.toString() !== id); await user.save(); res.status(200).json({ message: 'Order deleted successfully' }); }); const getAnalytics = asyncHandler(async (req, res) => { const { period = '30d' } = req.query; let startDate; const endDate = new Date(); switch (period) { case '7d': startDate = new Date(endDate.getTime() - 7 * 24 * 60 * 60 * 1000); break; case '30d': startDate = new Date(endDate.getTime() - 30 * 24 * 60 * 60 * 1000); break; case '90d': startDate = new Date(endDate.getTime() - 90 * 24 * 60 * 60 * 1000); break; default: startDate = new Date(endDate.getTime() - 30 * 24 * 60 * 60 * 1000); } const userGrowth = await User.aggregate([ { $match: { createdAt: { $gte: startDate, $lte: endDate } } }, { $group: { _id: { year: { $year: '$createdAt' }, month: { $month: '$createdAt' }, day: { $dayOfMonth: '$createdAt' } }, count: { $sum: 1 } } }, { $sort: { '_id.year': 1, '_id.month': 1, '_id.day': 1 } } ]); const allUsers = await User.find({ 'orders.createdAt': { $gte: startDate, $lte: endDate } }); const revenueData = []; const orderData = []; const categoryRevenue = {}; const productPerformance = {}; allUsers.forEach(user => { user.orders.forEach(order => { if (order.createdAt >= startDate && order.createdAt <= endDate) { const dateKey = order.createdAt.toISOString().split('T')[0]; const orderAmount = order.amount || 0; const existingRevenue = revenueData.find(item => item.date === dateKey); if (existingRevenue) { existingRevenue.revenue += orderAmount; } else { revenueData.push({ date: dateKey, revenue: orderAmount }); } const existingOrder = orderData.find(item => item.date === dateKey); if (existingOrder) { existingOrder.orders += 1; } else { orderData.push({ date: dateKey, orders: 1 }); } order.orderItems?.forEach(item => { if (item.category) { categoryRevenue[item.category] = (categoryRevenue[item.category] || 0) + (item.price * item.qty); } if (item.productId) { productPerformance[item.productId] = (productPerformance[item.productId] || 0) + (item.price * item.qty); } }); } }); }); revenueData.sort((a, b) => new Date(a.date) - new Date(b.date)); orderData.sort((a, b) => new Date(a.date) - new Date(b.date)); const topCategories = Object.entries(categoryRevenue) .map(([category, revenue]) => ({ category, revenue })) .sort((a, b) => b.revenue - a.revenue) .slice(0, 10); const topProductIds = Object.entries(productPerformance) .sort((a, b) => b[1] - a[1]) .slice(0, 10) .map(([productId]) => productId); const topProducts = await ProductModel.find({ _id: { $in: topProductIds } }) .select('name price category ratings numOfReviews'); const userEngagement = await User.aggregate([ { $match: { createdAt: { $gte: startDate, $lte: endDate } } }, { $project: { hasOrders: { $gt: [{ $size: '$orders' }, 0] }, orderCount: { $size: '$orders' }, totalSpent: { $sum: '$orders.amount' }, lastOrderDate: { $max: '$orders.createdAt' } } }, { $group: { _id: null, totalUsers: { $sum: 1 }, usersWithOrders: { $sum: { $cond: ['$hasOrders', 1, 0] } }, avgOrdersPerUser: { $avg: '$orderCount' }, avgSpendingPerUser: { $avg: '$totalSpent' } } } ]); const geographicData = await User.aggregate([ { $match: { createdAt: { $gte: startDate, $lte: endDate } } }, { $group: { _id: '$shippingAddress.state', count: { $sum: 1 } } }, { $sort: { count: -1 } } ]); const conversionFunnel = { totalVisitors: userEngagement[0]?.totalUsers || 0, registeredUsers: userEngagement[0]?.totalUsers || 0, usersWithOrders: userEngagement[0]?.usersWithOrders || 0, conversionRate: userEngagement[0]?.totalUsers > 0 ? ((userEngagement[0]?.usersWithOrders / userEngagement[0]?.totalUsers) * 100).toFixed(2) : 0 }; res.status(200).json({ period, userGrowth, revenueData, orderData, topCategories, topProducts, userEngagement: userEngagement[0] || {}, geographicData, conversionFunnel, summary: { totalRevenue: revenueData.reduce((sum, item) => sum + item.revenue, 0), totalOrders: orderData.reduce((sum, item) => sum + item.orders, 0), avgOrderValue: orderData.reduce((sum, item) => sum + item.orders, 0) > 0 ? (revenueData.reduce((sum, item) => sum + item.revenue, 0) / orderData.reduce((sum, item) => sum + item.orders, 0)).toFixed(2) : 0 } }); }); const getSystemInfo = asyncHandler(async (req, res) => { const systemInfo = { nodeVersion: process.version, platform: process.platform, memory: process.memoryUsage(), uptime: process.uptime(), environment: process.env.NODE_ENV, database: { connected: mongoose.connection.readyState === 1, host: mongoose.connection.host, name: mongoose.connection.name } }; res.status(200).json(systemInfo); }); const getAdminActivityLog = asyncHandler(async (req, res) => { const page = parseInt(req.query.page) || 1; const limit = parseInt(req.query.limit) || 50; const adminId = req.query.adminId; const skip = (page - 1) * limit; let query = {}; if (adminId) { query._id = adminId; } const admins = await Admin.find(query) .select('firstName lastName username activityLog') .sort({ 'activityLog.timestamp': -1 }) .skip(skip) .limit(limit); const activityLogs = []; admins.forEach(admin => { admin.activityLog.forEach(log => { activityLogs.push({ adminName: admin.getFullName(), adminUsername: admin.username, ...log.toObject() }); }); }); activityLogs.sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp)); res.status(200).json({ activityLogs: activityLogs.slice(0, limit), pagination: { page, limit, total: activityLogs.length } }); }); const getAllCategories = asyncHandler(async (req, res) => { const categories = await ProductModel.distinct('category'); res.status(200).json({ success: true, categories: categories.sort() }); }); const createCategory = asyncHandler(async (req, res) => { const { name } = req.body; if (!name || name.trim() === '') { res.status(400); throw new Error('Category name is required'); } const trimmedName = name.trim(); const existingCategory = await ProductModel.findOne({ category: trimmedName }); if (existingCategory) { res.status(400); throw new Error('Category already exists'); } res.status(201).json({ success: true, message: 'Category created successfully', category: trimmedName }); }); const ensureCategoryExists = async (categoryName) => { if (!categoryName || categoryName.trim() === '') { return false; } const trimmedName = categoryName.trim(); const existingCategory = await ProductModel.findOne({ category: trimmedName }); if (existingCategory) { return true; } return true; }; module.exports = { adminLogin, adminLogout, getAdminProfile, updateAdminProfile, getAllUsers, getUserById, updateUser, deleteUser, createUser, getAllProducts, createProduct, updateProduct, deleteProduct, uploadProductImages, getAllOrders, getOrderById, updateOrder, deleteOrder, getDashboardStats, getAnalytics, getSystemInfo, getAdminActivityLog, getAllCategories, createCategory };