const express = require("express");
const path = require("path");
const multer = require("multer");
const { PDFDocument } = require("pdf-lib");
const { encryptPDF } = require('cryptpdf');
const axios = require('axios');
const cookieParser = require('cookie-parser');
const session = require('express-session');
require('dotenv').config();

const csvParser = require('csv-parser');
const { Parser } = require('json2csv');
const { Readable } = require('stream');

// ================== Firebase Setup ==================
let admin;
let db;
let storage;
let bucket;
try {
    admin = require('firebase-admin');
    const serviceAccount = require('./serviceAccount.json');
    if (admin.apps.length === 0) {
        admin.initializeApp({
            credential: admin.credential.cert(serviceAccount),
            storageBucket: process.env.FIREBASE_STORAGE_BUCKET || `${serviceAccount.project_id}.appspot.com`
        });
    }
    db = admin.firestore();
    storage = admin.storage();
    bucket = storage.bucket();
    console.log('Firebase initialized successfully');
} catch (error) {
    console.error('Failed to initialize Firebase:', error.message);
    console.log('Firebase features disabled.');
    db = null;
    storage = null;
    bucket = null;
}

// ================== Express Setup ==================
const app = express();
const PORT = process.env.PORT || 3000;
const basePath = process.env.APP_URI || '/';
console.log(`Base path: ${basePath}`);

app.set('trust proxy', true);

// Session middleware for dashboard authentication
app.use(cookieParser());
app.use(session({
    secret: process.env.SESSION_SECRET || 'popiforce-super-secret-key-change-me',
    resave: false,
    saveUninitialized: false,
    cookie: { 
        secure: process.env.NODE_ENV === 'production',
        maxAge: 24 * 60 * 60 * 1000 // 24 hours
    }
}));

app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(basePath, express.static(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'public')));

// Multer setups
const upload = multer({
    storage: multer.memoryStorage(),
    limits: { fileSize: 10 * 1024 * 1024 },
    fileFilter: (req, file, cb) => {
        if (file.mimetype === 'application/pdf') cb(null, true);
        else cb(new Error('Only PDF files are allowed'), false);
    }
});
const uploadContact = multer().none();

// ================== Authentication Middleware ==================

/**
 * Verify Firebase ID token from Authorization header
 */
async function verifyFirebaseToken(token) {
    try {
        if (!token) return null;
        const decodedToken = await admin.auth().verifyIdToken(token);
        return decodedToken;
    } catch (error) {
        console.error('Token verification failed:', error.message);
        return null;
    }
}

/**
 * Middleware to protect dashboard routes
 */
async function requireAuth(req, res, next) {
    // Check if user is logged in via session
    if (req.session && req.session.user) {
        return next();
    }

    // Check Authorization header for API requests
    const authHeader = req.headers.authorization;
    if (authHeader && authHeader.startsWith('Bearer ')) {
        const token = authHeader.substring(7);
        const decoded = await verifyFirebaseToken(token);
        if (decoded) {
            req.user = decoded;
            return next();
        }
    }

    // If AJAX request, return 401 JSON
    if (req.xhr || req.headers.accept?.includes('application/json')) {
        return res.status(401).json({ success: false, message: 'Authentication required' });
    }

    // Redirect to login for page requests
    res.redirect('/login');
}

/**
 * Middleware to check if user is an admin
 * (You can check custom claims or a Firestore admin list)
 */
async function requireAdmin(req, res, next) {
    const uid = req.user?.uid || req.session?.user?.uid;
    if (!uid) {
        return res.status(403).json({ success: false, message: 'Admin access required' });
    }

    try {
        // Option 1: Check custom claims
        const user = await admin.auth().getUser(uid);
        if (user.customClaims && user.customClaims.admin === true) {
            return next();
        }

        // Option 2: Check Firestore admin list
        const adminDoc = await db.collection('admins').doc(uid).get();
        if (adminDoc.exists && adminDoc.data().isAdmin === true) {
            return next();
        }

        return res.status(403).json({ success: false, message: 'Admin access required' });
    } catch (error) {
        console.error('Admin check failed:', error);
        return res.status(500).json({ success: false, message: 'Error checking admin status' });
    }
}

// Multer setup for CSV uploads
const uploadCSV = multer({
    storage: multer.memoryStorage(),
    limits: { fileSize: 10 * 1024 * 1024 },
    fileFilter: (req, file, cb) => {
        // Accept CSV files
        if (file.mimetype === 'text/csv' || file.originalname.endsWith('.csv')) {
            cb(null, true);
        } else {
            cb(new Error('Only CSV files are allowed'), false);
        }
    }
});

// ================== Rate Limiting ==================
const memoryRateLimits = new Map();

function getClientIp(req) {
    const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress || req.socket.remoteAddress || req.ip;
    return (ip && ip.split(',')[0].trim()) || 'unknown';
}

async function checkRateLimit(ip) {
    const limit = 2;
    const windowMs = 24 * 60 * 60 * 1000;

    if (db) {
        try {
            const docRef = db.collection('rate_limits').doc(ip);
            const doc = await docRef.get();

            if (!doc.exists) {
                await docRef.set({
                    count: 1,
                    firstRequestAt: admin.firestore.FieldValue.serverTimestamp(),
                    lastRequestAt: admin.firestore.FieldValue.serverTimestamp()
                });
                return { allowed: true };
            }

            const data = doc.data();
            const firstRequestAt = data.firstRequestAt?.toDate?.() || new Date(data.firstRequestAt);
            const now = new Date();

            if (now - firstRequestAt > windowMs) {
                await docRef.update({
                    count: 1,
                    firstRequestAt: admin.firestore.FieldValue.serverTimestamp(),
                    lastRequestAt: admin.firestore.FieldValue.serverTimestamp()
                });
                return { allowed: true };
            }

            const currentCount = data.count || 0;
            if (currentCount >= limit) {
                return { allowed: false, message: `Daily limit of ${limit} submissions reached. Try again tomorrow.` };
            }

            await docRef.update({
                count: currentCount + 1,
                lastRequestAt: admin.firestore.FieldValue.serverTimestamp()
            });
            return { allowed: true };
        } catch (error) {
            console.error('Rate limit error:', error);
            return { allowed: true };
        }
    }

    // In-memory fallback
    if (!memoryRateLimits.has(ip)) {
        memoryRateLimits.set(ip, { count: 1, firstRequest: Date.now() });
        return { allowed: true };
    }

    const record = memoryRateLimits.get(ip);
    const now = Date.now();
    if (now - record.firstRequest > windowMs) {
        memoryRateLimits.set(ip, { count: 1, firstRequest: now });
        return { allowed: true };
    }

    if (record.count >= limit) {
        return { allowed: false, message: `Daily limit of ${limit} submissions reached. Try again tomorrow.` };
    }

    record.count++;
    return { allowed: true };
}

// ================== Brevo Email Functions ==================
const BREVO_API_KEY = process.env.BREVO_API_KEY;
const SENDER_EMAIL = 'comms@inter-net.co.za';
const COMPANY_NAME = 'POPIFORCE';

async function sendEmail(subject, senderName, recipientEmail, recipientName, htmlContent) {
    if (!BREVO_API_KEY) {
        console.error('BREVO_API_KEY is not set.');
        return;
    }
    const payload = {
        sender: { name: senderName, email: SENDER_EMAIL },
        to: [{ email: recipientEmail, name: recipientName || recipientEmail }],
        subject: subject,
        htmlContent: htmlContent
    };
    try {
        const response = await axios.post('https://api.brevo.com/v3/smtp/email', payload, {
            headers: {
                'accept': 'application/json',
                'api-key': BREVO_API_KEY,
                'content-type': 'application/json'
            }
        });
        console.log(`Email sent to ${recipientEmail} (${subject})`);
        return response.data;
    } catch (error) {
        console.error('Brevo email error:', error.response ? error.response.data : error.message);
        throw error;
    }
}

async function sendEncryptedPDFEmail(userName, userEmail, password, downloadUrl) {
    const subject = 'Your Encrypted Payslip is Ready - POPIFORCE';
    const htmlContent = `
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"></head>
<body style="font-family: 'Segoe UI', Arial, sans-serif; background-color: #f4f7fb; padding: 20px; margin: 0;">
    <div style="max-width: 600px; background: #ffffff; padding: 35px; border-radius: 16px; box-shadow: 0 4px 12px rgba(0,0,0,0.05); margin: 0 auto;">
        <div style="text-align: center; border-bottom: 2px solid #3f64bb; padding-bottom: 20px;">
            <h1 style="color: #3f64bb; margin: 0; font-size: 28px;">POPIFORCE</h1>
            <p style="color: #666; margin: 5px 0 0 0;">Secure Payslip Encryption</p>
        </div>
        <p style="font-size: 16px; color: #333;">Dear ${userName},</p>
        <p style="font-size: 16px; color: #333;">Your payslip has been successfully encrypted and is now available for secure download.</p>
        <div style="background-color: #eef2ff; border-radius: 12px; padding: 20px; margin: 25px 0;">
            <p style="margin: 0; font-weight: bold; color: #3f64bb;">Your password to open the PDF:</p>
            <p style="margin: 8px 0 0 0; font-family: 'Courier New', monospace; font-size: 22px; color: #1e293b; letter-spacing: 1px;">${password}</p>
        </div>
        <div style="text-align: center; margin: 30px 0;">
            <a href="${downloadUrl}" style="background-color: #3f64bb; color: white; padding: 14px 40px; text-decoration: none; border-radius: 40px; font-weight: 600; display: inline-block;">Download Encrypted Payslip</a>
        </div>
        <p style="font-size: 13px; color: #777;">This link is valid for 7 days. Do not share your password with anyone.</p>
        <p style="font-size: 14px; color: #555;">If you have any questions, contact us at <a href="mailto:info@popiforce.co.za" style="color: #3f64bb;">info@popiforce.co.za</a>.</p>
        <div style="margin-top: 30px; padding-top: 20px; border-top: 1px solid #e2e8f0; font-size: 12px; color: #888; text-align: center;">
            &copy; 2025 POPIFORCE | Idea Pioneers<br>
            <a href="https://popiforce.co.za" style="color: #3f64bb; text-decoration: none;">popiforce.co.za</a>
        </div>
    </div>
</body>
</html>
    `;
    await sendEmail(subject, COMPANY_NAME, userEmail, userName, htmlContent);
}

async function sendAdminAlert(userName, userEmail, originalFileName, downloadUrl) {
    const subject = 'New POPIFORCE Encryption Request';
    const adminRecipients = ['sibusiso@ideapioneers.co.za', 'info@popiforce.co.za', 'sue-ann@ideapioneers.co.za'];
    const htmlContent = `
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"></head>
<body style="font-family: Arial, sans-serif; background-color: #f4f4f4; padding: 20px; margin: 0;">
    <div style="max-width: 650px; background: #ffffff; padding: 30px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); margin: 0 auto;">
        <div style="background-color: #3f64bb; text-align: center; padding: 20px; border-radius: 8px 8px 0 0; margin: -30px -30px 25px -30px;">
            <h1 style="color: #ffffff; margin: 0;">POPIFORCE</h1>
            <p style="color: #d0dfff; margin: 5px 0 0 0;">New Encryption Request</p>
        </div>
        <div style="background-color: #fef7e0; border-left: 4px solid #3f64bb; padding: 12px 15px; margin-bottom: 25px; border-radius: 4px;">
            <p style="margin: 0; font-weight: bold; color: #3f64bb;">A new payslip encryption request has been submitted.</p>
        </div>
        <div style="margin-bottom: 25px;">
            <h2 style="color: #3f64bb; font-size: 18px; margin: 0 0 15px 0; border-left: 3px solid #3f64bb; padding-left: 12px;">USER DETAILS</h2>
            <div style="background-color: #f9f9f9; border-radius: 12px; padding: 5px 0;">
                <div style="display: flex; padding: 12px 15px; border-bottom: 1px solid #eeeeee;">
                    <div style="width: 140px; font-weight: bold; color: #333;">Name:</div>
                    <div style="flex: 1; color: #555;">${userName}</div>
                </div>
                <div style="display: flex; padding: 12px 15px; border-bottom: 1px solid #eeeeee;">
                    <div style="width: 140px; font-weight: bold; color: #333;">Email:</div>
                    <div style="flex: 1; color: #555;">${userEmail}</div>
                </div>
                <div style="display: flex; padding: 12px 15px;">
                    <div style="width: 140px; font-weight: bold; color: #333;">Original File:</div>
                    <div style="flex: 1; color: #555;">${originalFileName}</div>
                </div>
            </div>
        </div>
        ${downloadUrl ? `<p style="text-align: center;"><a href="${downloadUrl}" style="color: #3f64bb;">Download Encrypted File</a></p>` : ''}
        <div style="margin-top: 30px; padding-top: 20px; border-top: 1px solid #eeeeee; font-size: 11px; color: #999; text-align: center;">
            &copy; 2025 POPIFORCE | Idea Pioneers
        </div>
    </div>
</body>
</html>
    `;
    for (const recipient of adminRecipients) {
        try {
            await sendEmail(subject, COMPANY_NAME, recipient, 'Admin', htmlContent);
        } catch (err) {
            console.error(`Failed to send admin alert to ${recipient}:`, err.message);
        }
    }
}

// ================== Routes ==================

// Public routes
app.get(basePath, (req, res) => {
    res.sendFile(path.join(__dirname, 'public', 'pages', 'home.html'));
});
app.get('/', (req, res) => {
    res.sendFile(path.join(__dirname, 'public', 'pages', 'home.html'));
});

// Login page (public)
app.get('/login', (req, res) => {
    // If already logged in, redirect to dashboard
    if (req.session && req.session.user) {
        return res.redirect('/dashboard');
    }
    res.sendFile(path.join(__dirname, 'public', 'pages', 'login.html'));
});

// Bulk email page (protected)
app.get('/bulk-email', requireAuth, (req, res) => {
    res.sendFile(path.join(__dirname, 'public', 'pages', 'bulk-email.html'));
});

// Login API endpoint
app.post('/api/login', async (req, res) => {
    try {
        const { idToken } = req.body;
        if (!idToken) {
            return res.status(400).json({ success: false, message: 'ID token required' });
        }

        // Verify the Firebase ID token
        const decodedToken = await admin.auth().verifyIdToken(idToken);
        const uid = decodedToken.uid;

        // Check if user is an admin (either custom claim or Firestore)
        let isAdmin = false;
        try {
            // Check custom claims
            const userRecord = await admin.auth().getUser(uid);
            if (userRecord.customClaims && userRecord.customClaims.admin === true) {
                isAdmin = true;
            }
        } catch (err) {}

        // If not admin via claims, check Firestore
        if (!isAdmin && db) {
            try {
                const adminDoc = await db.collection('admins').doc(uid).get();
                if (adminDoc.exists && adminDoc.data().isAdmin === true) {
                    isAdmin = true;
                }
            } catch (err) {}
        }

        if (!isAdmin) {
            return res.status(403).json({ success: false, message: 'Unauthorized. Admin access required.' });
        }

        // Set session
        req.session.user = {
            uid: uid,
            email: decodedToken.email,
            name: decodedToken.name || 'Admin'
        };
        req.session.isAdmin = true;

        res.json({ success: true, message: 'Login successful', redirect: '/dashboard' });
    } catch (error) {
        console.error('Login error:', error);
        res.status(401).json({ success: false, message: 'Authentication failed: ' + error.message });
    }
});

// Logout
app.get('/logout', (req, res) => {
    req.session.destroy(() => {
        res.redirect('/login');
    });
});

// Dashboard (protected)
app.get('/dashboard', requireAuth, (req, res) => {
    res.sendFile(path.join(__dirname, 'public', 'pages', 'dashboard.html'));
});

// API: Get encryption requests (for dashboard)
app.get('/api/encryption-requests', requireAuth, requireAdmin, async (req, res) => {
    try {
        const limit = parseInt(req.query.limit) || 50;
        const startAfter = req.query.startAfter;

        let query = db.collection('encryption_requests')
            .orderBy('timestamp', 'desc')
            .limit(limit);

        if (startAfter) {
            const doc = await db.collection('encryption_requests').doc(startAfter).get();
            if (doc.exists) {
                query = query.startAfter(doc);
            }
        }

        const snapshot = await query.get();
        const requests = [];
        snapshot.forEach(doc => {
            const data = doc.data();
            const timestamp = data.timestamp?.toDate?.() || new Date(data.timestamp);
            requests.push({
                id: doc.id,
                name: data.name || 'N/A',
                email: data.email || 'N/A',
                originalFileName: data.originalFileName || 'N/A',
                fileSize: data.fileSize || 0,
                timestamp: timestamp.toISOString(),
                storagePath: data.storagePath || null,
                downloadUrl: data.downloadUrl || null,
                ip: data.ip || 'N/A'
            });
        });

        const lastDoc = snapshot.docs[snapshot.docs.length - 1];
        res.json({
            success: true,
            data: requests,
            pagination: {
                hasMore: snapshot.docs.length === limit,
                lastId: lastDoc ? lastDoc.id : null
            }
        });
    } catch (error) {
        console.error('Error fetching encryption requests:', error);
        res.status(500).json({ success: false, message: 'Error fetching data' });
    }
});

// API: Get dashboard stats
app.get('/api/dashboard-stats', requireAuth, requireAdmin, async (req, res) => {
    try {
        // Total count
        const totalSnapshot = await db.collection('encryption_requests').get();
        const total = totalSnapshot.size;

        // Today's count
        const today = new Date();
        today.setHours(0, 0, 0, 0);
        const todaySnapshot = await db.collection('encryption_requests')
            .where('timestamp', '>=', today)
            .get();

        // Unique users (by email) - approximate
        const emailSet = new Set();
        totalSnapshot.forEach(doc => {
            const data = doc.data();
            if (data.email) emailSet.add(data.email);
        });

        res.json({
            success: true,
            stats: {
                total: total,
                today: todaySnapshot.size,
                uniqueUsers: emailSet.size
            }
        });
    } catch (error) {
        console.error('Error fetching stats:', error);
        res.status(500).json({ success: false, message: 'Error fetching stats' });
    }
});

// Public contact endpoint
app.post('/contact', uploadContact, async (req, res) => {
    try {
        const { fullname, phone, company, email_contact } = req.body;
        if (!fullname || !phone || !company || !email_contact) {
            return res.status(400).json({ success: false, message: "All fields are required." });
        }
        if (db) {
            await db.collection('contact_submissions').add({
                fullname: fullname.trim(),
                phone: phone.trim(),
                company: company.trim(),
                email: email_contact.trim(),
                timestamp: admin.firestore.FieldValue.serverTimestamp()
            });
            console.log(`Contact saved for ${fullname}`);
        }
        res.json({ success: true, message: "Thank you! We'll contact you shortly." });
    } catch (error) {
        console.error("Contact save error:", error);
        res.status(500).json({ success: false, message: "Error saving your request." });
    }
});

// Encryption endpoint (with rate limiting)
app.post('/encrypt-pdf', upload.single("pdfFile"), async (req, res) => {
    const clientIp = getClientIp(req);
    console.log(`Encryption request from IP: ${clientIp}`);

    const rateResult = await checkRateLimit(clientIp);
    if (!rateResult.allowed) {
        return res.status(429).json({
            success: false,
            message: rateResult.message || 'Rate limit exceeded. Please try again later.'
        });
    }

    try {
        const { name, email, password } = req.body;
        const pdfFile = req.file;

        if (!pdfFile) return res.status(400).json({ success: false, message: "No PDF uploaded." });
        if (!password) return res.status(400).json({ success: false, message: "Password is required." });
        if (!name || !email) return res.status(400).json({ success: false, message: "Name and email are required." });

        let docRef;
        if (db) {
            docRef = db.collection('encryption_requests').doc();
            await docRef.set({
                name: name.trim(),
                email: email.trim(),
                originalFileName: pdfFile.originalname,
                fileSize: pdfFile.size,
                ip: clientIp,
                timestamp: admin.firestore.FieldValue.serverTimestamp(),
            });
            console.log(`Saved encryption request ${docRef.id} for ${email}`);
        }

        const pdfBytes = pdfFile.buffer;
        const pdfDoc = await PDFDocument.load(pdfBytes);
        const originalPdfBytes = await pdfDoc.save();
        const encryptedPdfBytes = await encryptPDF(originalPdfBytes, password, "popiforce2024");

        const fileId = docRef ? docRef.id : Date.now().toString();
        const fileName = `encrypted/${fileId}_${email}_${Date.now()}.pdf`;

        let downloadUrl = null;
        if (bucket) {
            const file = bucket.file(fileName);
            await file.save(encryptedPdfBytes, { contentType: 'application/pdf' });
            const [signedUrl] = await file.getSignedUrl({
                action: 'read',
                expires: Date.now() + 7 * 24 * 60 * 60 * 1000
            });
            downloadUrl = signedUrl;
            console.log(`File uploaded to Firebase Storage: ${fileName}`);
        } else {
            console.error('Firebase Storage not available');
            return res.status(500).json({ success: false, message: "Storage is not available." });
        }

        if (db && docRef) {
            await docRef.update({
                encryptedAt: admin.firestore.FieldValue.serverTimestamp(),
                storagePath: fileName,
                downloadUrl: downloadUrl
            });
        }

        await sendEncryptedPDFEmail(name, email, password, downloadUrl)
            .catch(err => console.error('Failed to send user email:', err.message));

        await sendAdminAlert(name, email, pdfFile.originalname, downloadUrl)
            .catch(err => console.error('Failed to send admin alert:', err.message));

        res.json({ success: true, message: "Check your email for the encrypted PDF." });

    } catch (error) {
        console.error("Encryption error:", error);
        res.status(500).json({ success: false, message: `Error: ${error.message}` });
    }
});

app.listen(PORT, () => {
    console.log(`Server listening on port ${PORT}`);
    console.log(`Base path: ${basePath}`);
});

// ================== Bulk Campaign Endpoints ==================

// Store uploaded files temporarily (in-memory for this example)
// In production, you'd use a temporary folder or Firebase Storage
const tempFileStore = {};

/**
 * Upload multiple PDF files for bulk campaign
 */
app.post('/api/admin/upload-batch', requireAuth, requireAdmin, upload.array('pdfFiles', 100), async (req, res) => {
    try {
        const files = req.files;
        if (!files || files.length === 0) {
            return res.status(400).json({ success: false, message: 'No files uploaded' });
        }

        // Validate all files are PDFs
        for (const file of files) {
            if (file.mimetype !== 'application/pdf') {
                return res.status(400).json({ 
                    success: false, 
                    message: `File "${file.originalname}" is not a PDF` 
                });
            }
        }

        // Store files in session
        const sessionId = Date.now().toString();
        tempFileStore[sessionId] = {
            files: files,
            uploadedAt: new Date().toISOString()
        };

        // Generate CSV template with filenames
        const csvData = files.map(file => ({
            filename: file.originalname,
            email: '',
            password: ''
        }));

        const parser = new Parser();
        const csv = parser.parse(csvData);

        res.json({
            success: true,
            sessionId: sessionId,
            fileCount: files.length,
            csvTemplate: csv,
            message: 'Files uploaded successfully. Download the CSV template to populate user data.'
        });

    } catch (error) {
        console.error('Upload batch error:', error);
        res.status(500).json({ success: false, message: `Upload failed: ${error.message}` });
    }
});

/**
 * Download CSV template with filenames
 */
app.get('/api/admin/download-csv/:sessionId', requireAuth, requireAdmin, (req, res) => {
    try {
        const sessionId = req.params.sessionId;
        const session = tempFileStore[sessionId];
        
        if (!session) {
            return res.status(404).json({ success: false, message: 'Session not found' });
        }

        const csvData = session.files.map(file => ({
            filename: file.originalname,
            email: '',
            password: ''
        }));

        const parser = new Parser();
        const csv = parser.parse(csvData);

        res.setHeader('Content-Type', 'text/csv');
        res.setHeader('Content-Disposition', 'attachment; filename=campaign_template.csv');
        res.send(csv);

    } catch (error) {
        console.error('Download CSV error:', error);
        res.status(500).json({ success: false, message: error.message });
    }
});

/**
 * Validate and process CSV file
 */
app.post('/api/admin/validate-csv/:sessionId', requireAuth, requireAdmin, uploadCSV.single('csvFile'), async (req, res) => {
    try {
        const sessionId = req.params.sessionId;
        const session = tempFileStore[sessionId];
        
        if (!session) {
            return res.status(404).json({ success: false, message: 'Session not found' });
        }

        if (!req.file) {
            return res.status(400).json({ success: false, message: 'CSV file is required' });
        }

        // Parse CSV
        const csvData = [];
        const csvBuffer = req.file.buffer;
        const readableStream = new Readable();
        readableStream.push(csvBuffer);
        readableStream.push(null);

        await new Promise((resolve, reject) => {
            readableStream
                .pipe(csvParser())
                .on('data', (row) => csvData.push(row))
                .on('end', resolve)
                .on('error', reject);
        });

        // Validate CSV data
        const uploadedFileNames = session.files.map(f => f.originalname);
        const errors = [];
        const validRecords = [];

        for (let i = 0; i < csvData.length; i++) {
            const record = csvData[i];
            const rowNumber = i + 2; // +2 because of header and 0-index

            // Check required fields
            if (!record.filename || !record.email || !record.password) {
                errors.push(`Row ${rowNumber}: Missing required fields (filename, email, password)`);
                continue;
            }

            // Check if file exists in uploaded files
            if (!uploadedFileNames.includes(record.filename)) {
                errors.push(`Row ${rowNumber}: File "${record.filename}" not found in uploaded files`);
                continue;
            }

            // Validate email format
            const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
            if (!emailRegex.test(record.email)) {
                errors.push(`Row ${rowNumber}: Invalid email format: "${record.email}"`);
                continue;
            }

            // Validate password (at least 6 characters)
            if (record.password.length < 6) {
                errors.push(`Row ${rowNumber}: Password must be at least 6 characters`);
                continue;
            }

            // Find the file object
            const fileObj = session.files.find(f => f.originalname === record.filename);
            validRecords.push({
                filename: record.filename,
                email: record.email.trim(),
                password: record.password,
                fileBuffer: fileObj.buffer,
                fileSize: fileObj.size
            });
        }

        // If errors exist, return them
        if (errors.length > 0) {
            return res.status(400).json({
                success: false,
                errors: errors,
                validCount: validRecords.length,
                errorCount: errors.length,
                message: 'Validation failed. Please fix the errors and try again.'
            });
        }

        // Store valid records in session for processing
        session.validRecords = validRecords;

        res.json({
            success: true,
            message: `Validation successful! ${validRecords.length} records ready to process.`,
            recordCount: validRecords.length,
            records: validRecords.map(r => ({ filename: r.filename, email: r.email }))
        });

    } catch (error) {
        console.error('Validate CSV error:', error);
        res.status(500).json({ success: false, message: error.message });
    }
});

/**
 * Process and send bulk encrypted emails
 */
app.post('/api/admin/send-bulk/:sessionId', requireAuth, requireAdmin, async (req, res) => {
    try {
        const campaignId = `campaign_${Date.now()}_${Math.random().toString(36).substring(7)}`;
        const sessionId = req.params.sessionId;
        const session = tempFileStore[sessionId];
        
        if (!session) {
            return res.status(404).json({ success: false, message: 'Session not found' });
        }

        if (!session.validRecords || session.validRecords.length === 0) {
            return res.status(400).json({ 
                success: false, 
                message: 'No valid records found. Please validate the CSV first.' 
            });
        }

        const { emailSubject, emailMessage } = req.body;
        const results = {
            total: session.validRecords.length,
            successful: [],
            failed: []
        };

        // Process each record
        for (const record of session.validRecords) {
            try {
                // Load and encrypt PDF
                const pdfBytes = record.fileBuffer;
                const pdfDoc = await PDFDocument.load(pdfBytes);
                const originalPdfBytes = await pdfDoc.save();
                const encryptedPdfBytes = await encryptPDF(originalPdfBytes, record.password, "popiforce2024");

                // Upload to Firebase Storage
                const fileId = Date.now().toString() + Math.random().toString(36).substring(7);
                const fileName = `bulk/${fileId}_${record.email}_${Date.now()}.pdf`;
                
                let downloadUrl = null;
                if (bucket) {
                    const file = bucket.file(fileName);
                    await file.save(encryptedPdfBytes, { contentType: 'application/pdf' });
                    const [signedUrl] = await file.getSignedUrl({
                        action: 'read',
                        expires: Date.now() + 7 * 24 * 60 * 60 * 1000
                    });
                    downloadUrl = signedUrl;
                }

                // Save to Firestore
                if (db) {
                    await db.collection('encryption_requests').add({
                        name: record.email.split('@')[0] || 'User',
                        email: record.email,
                        originalFileName: record.filename,
                        fileSize: record.fileSize,
                        storagePath: fileName,
                        downloadUrl: downloadUrl,
                        isBulk: true,
                        campaignId: campaignId,
                        sentAt: admin.firestore.FieldValue.serverTimestamp(),
                        timestamp: admin.firestore.FieldValue.serverTimestamp()
                    });
                }

                // Send email to user
                await sendBulkEncryptedPDFEmail(
                    record.email.split('@')[0] || 'User',
                    record.email,
                    record.password,
                    downloadUrl,
                    emailSubject,
                    emailMessage
                );

                // Save campaign summary
                await db.collection('campaigns').doc(campaignId).set({
                    campaignId: campaignId,
                    total: results.total,
                    successful: results.successful.length,
                    failed: results.failed.length,
                    subject: emailSubject,
                    sentAt: admin.firestore.FieldValue.serverTimestamp(),
                    createdBy: req.session.user?.uid || 'admin'
                });

                results.successful.push({
                    email: record.email,
                    filename: record.filename
                });

            } catch (error) {
                console.error(`Failed to process ${record.email}:`, error);
                results.failed.push({
                    email: record.email,
                    filename: record.filename,
                    error: error.message
                });
            }
        }

        // Clean up session data
        delete tempFileStore[sessionId];

        res.json({
            success: true,
            results: results,
            message: `Bulk email campaign completed. ${results.successful.length} sent, ${results.failed.length} failed.`
        });

    } catch (error) {
        console.error('Send bulk error:', error);
        res.status(500).json({ success: false, message: error.message });
    }
});

/**
 * Get campaign status (optional)
 */
app.get('/api/admin/campaigns', requireAuth, requireAdmin, async (req, res) => {
    try {
        const snapshot = await db.collection('encryption_requests')
            .where('isBulk', '==', true)
            .orderBy('sentAt', 'desc')
            .limit(50)
            .get();

        const campaigns = [];
        snapshot.forEach(doc => {
            const data = doc.data();
            campaigns.push({
                id: doc.id,
                email: data.email,
                filename: data.originalFileName,
                sentAt: data.sentAt?.toDate?.() || data.timestamp?.toDate?.() || new Date(),
                downloadUrl: data.downloadUrl
            });
        });

        res.json({ success: true, data: campaigns });
    } catch (error) {
        console.error('Fetch campaigns error:', error);
        res.status(500).json({ success: false, message: error.message });
    }
});

/**
 * Get all bulk campaigns (summary)
 */
app.get('/api/admin/bulk-campaigns', requireAuth, requireAdmin, async (req, res) => {
    try {
        const limit = parseInt(req.query.limit) || 50;
        const snapshot = await db.collection('campaigns')
            .orderBy('sentAt', 'desc')
            .limit(limit)
            .get();

        const campaigns = [];
        snapshot.forEach(doc => {
            const data = doc.data();
            campaigns.push({
                id: doc.id,
                campaignId: data.campaignId,
                total: data.total || 0,
                successful: data.successful || 0,
                failed: data.failed || 0,
                subject: data.subject || 'No subject',
                sentAt: data.sentAt?.toDate?.() || new Date()
            });
        });

        res.json({ success: true, data: campaigns });
    } catch (error) {
        console.error('Error fetching campaigns:', error);
        res.status(500).json({ success: false, message: error.message });
    }
});

/**
 * Get details of a specific campaign (list of recipients)
 */
app.get('/api/admin/bulk-campaign/:campaignId', requireAuth, requireAdmin, async (req, res) => {
    try {
        const campaignId = req.params.campaignId;
        const snapshot = await db.collection('encryption_requests')
            .where('campaignId', '==', campaignId)
            .orderBy('sentAt', 'desc')
            .get();

        const recipients = [];
        snapshot.forEach(doc => {
            const data = doc.data();
            recipients.push({
                id: doc.id,
                email: data.email || 'N/A',
                name: data.name || 'N/A',
                originalFileName: data.originalFileName || 'N/A',
                downloadUrl: data.downloadUrl || null,
                sentAt: data.sentAt?.toDate?.() || data.timestamp?.toDate?.() || new Date()
            });
        });

        res.json({ success: true, data: recipients });
    } catch (error) {
        console.error('Error fetching campaign:', error);
        res.status(500).json({ success: false, message: error.message });
    }
});

/**
 * Send bulk encrypted PDF email with custom template
 */
async function sendBulkEncryptedPDFEmail(userName, userEmail, password, downloadUrl, customSubject, customMessage) {
    const subject = customSubject || 'Your Encrypted Payslip - POPIFORCE';
    
    const htmlContent = `
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"></head>
<body style="font-family: 'Segoe UI', Arial, sans-serif; background-color: #f4f7fb; padding: 20px; margin: 0;">
    <div style="max-width: 600px; background: #ffffff; padding: 35px; border-radius: 16px; box-shadow: 0 4px 12px rgba(0,0,0,0.05); margin: 0 auto;">
        <div style="text-align: center; border-bottom: 2px solid #3f64bb; padding-bottom: 20px;">
            <h1 style="color: #3f64bb; margin: 0; font-size: 28px;">POPIFORCE</h1>
            <p style="color: #666; margin: 5px 0 0 0;">Secure Payslip Encryption</p>
        </div>
        <p style="font-size: 16px; color: #333;">Dear ${userName},</p>
        ${customMessage ? `<div style="background-color: #f8fafc; padding: 15px; border-radius: 8px; margin: 15px 0;">${customMessage}</div>` : ''}
        <p style="font-size: 16px; color: #333;">Your payslip has been successfully encrypted and is now available for secure download.</p>
        <div style="background-color: #eef2ff; border-radius: 12px; padding: 20px; margin: 25px 0;">
            <p style="margin: 0; font-weight: bold; color: #3f64bb;">Your password to open the PDF:</p>
            <p style="margin: 8px 0 0 0; font-family: 'Courier New', monospace; font-size: 22px; color: #1e293b; letter-spacing: 1px;">${password}</p>
        </div>
        <div style="text-align: center; margin: 30px 0;">
            <a href="${downloadUrl}" style="background-color: #3f64bb; color: white; padding: 14px 40px; text-decoration: none; border-radius: 40px; font-weight: 600; display: inline-block;">Download Encrypted Payslip</a>
        </div>
        <p style="font-size: 13px; color: #777;">This link is valid for 7 days. Do not share your password with anyone.</p>
        <p style="font-size: 14px; color: #555;">If you have any questions, contact us at <a href="mailto:info@popiforce.co.za" style="color: #3f64bb;">info@popiforce.co.za</a>.</p>
        <div style="margin-top: 30px; padding-top: 20px; border-top: 1px solid #e2e8f0; font-size: 12px; color: #888; text-align: center;">
            &copy; 2025 POPIFORCE | Idea Pioneers<br>
            <a href="https://popiforce.co.za" style="color: #3f64bb; text-decoration: none;">popiforce.co.za</a>
        </div>
    </div>
</body>
</html>
    `;

    await sendEmail(subject, COMPANY_NAME, userEmail, userName, htmlContent);
}