const nocodbService = require('../services/nocodb');
const config = require('../config');
const logger = require('../utils/logger');
const { sendEmail } = require('../services/email');
const emailTemplates = require('../services/emailTemplates');
const crypto = require('crypto');

class PublicShiftsController {
    // Get all public shifts (without volunteer counts)
    async getPublicShifts(req, res) {
        try {
            if (!config.nocodb.shiftsSheetId) {
                return res.status(500).json({
                    success: false,
                    error: 'Shifts not configured'
                });
            }

            const response = await nocodbService.getAll(config.nocodb.shiftsSheetId, {
                sort: 'Date,Start Time'
            });

            // More flexible filtering - check for Public field being truthy or not explicitly false
            const shifts = (response.list || []).filter(shift => {
                // Skip cancelled shifts
                if (shift.Status === 'Cancelled') {
                    return false;
                }
                
                // If Public field doesn't exist, include the shift (backwards compatibility)
                if (shift.Public === undefined || shift.Public === null) {
                    logger.info(`Shift ${shift.Title} has no Public field, including it`);
                    return true;
                }
                
                // Check for various truthy values (true, "true", 1, "1", "yes", etc.)
                const publicValue = String(shift.Public).toLowerCase();
                return publicValue === 'true' || publicValue === '1' || publicValue === 'yes';
            });

            logger.info(`Found ${shifts.length} public shifts out of ${response.list?.length || 0} total`);

            res.json({
                success: true,
                shifts: shifts
            });
        } catch (error) {
            logger.error('Error fetching public shifts:', error);
            res.status(500).json({
                success: false,
                error: 'Failed to fetch shifts'
            });
        }
    }

    // Get single shift details for direct linking
    async getShiftById(req, res) {
        try {
            const { id } = req.params;
            const shift = await nocodbService.getById(config.nocodb.shiftsSheetId, id);
            
            if (!shift || shift.Status === 'Cancelled') {
                return res.status(404).json({
                    success: false,
                    error: 'Shift not found'
                });
            }

            // Similar flexible check for single shift
            if (shift.Public !== undefined && shift.Public !== null) {
                const publicValue = String(shift.Public).toLowerCase();
                const isPublic = publicValue === 'true' || publicValue === '1' || publicValue === 'yes';
                if (!isPublic) {
                    return res.status(404).json({
                        success: false,
                        error: 'Shift not found'
                    });
                }
            }

            res.json({
                success: true,
                shift
            });
        } catch (error) {
            logger.error('Error fetching shift:', error);
            res.status(500).json({
                success: false,
                error: 'Failed to fetch shift'
            });
        }
    }

    // Public signup - creates temp user and signs them up
    async publicSignup(req, res) {
        try {
            const { id } = req.params;
            const { email, name, phone } = req.body;

            if (!email || !name) {
                return res.status(400).json({
                    success: false,
                    error: 'Email and name are required'
                });
            }

            // Get shift details
            const shift = await nocodbService.getById(config.nocodb.shiftsSheetId, id);
            logger.info('Raw shift data retrieved:', JSON.stringify(shift, null, 2));
            
            if (!shift || shift.Status === 'Cancelled') {
                return res.status(404).json({
                    success: false,
                    error: 'Shift not found or cancelled'
                });
            }

            // Check if shift is full
            if (shift['Current Volunteers'] >= shift['Max Volunteers']) {
                return res.status(400).json({
                    success: false,
                    error: 'This shift is full'
                });
            }

            // Check if user exists
            let user = await nocodbService.getUserByEmail(email);
            let isNewUser = false;
            let tempPassword = null;

            if (!user) {
                // Generate temp password using instance method
                const controller = new PublicShiftsController();
                tempPassword = controller.generateTempPassword();
                
                const shiftDate = new Date(shift.Date);
                const expiresAt = new Date(shiftDate);
                expiresAt.setDate(expiresAt.getDate() + 1); // Expires day after shift

                const userData = {
                    Email: email,
                    Password: tempPassword,
                    Name: name,
                    UserType: 'temp',
                    'User Type': 'temp',
                    ExpiresAt: expiresAt.toISOString()
                };

                logger.info('Creating temp user with data:', JSON.stringify(userData, null, 2));
                user = await nocodbService.create(config.nocodb.loginSheetId, userData);
                isNewUser = true;
                logger.info(`Created temp user ${email} for shift ${id}`);
            }

            // Check if already signed up
            const allSignups = await nocodbService.getAllPaginated(config.nocodb.shiftSignupsSheetId);
            const existingSignup = (allSignups.list || []).find(s => 
                s['Shift ID'] === parseInt(id) && 
                s['User Email'] === email && 
                s.Status === 'Confirmed'
            );

            if (existingSignup) {
                return res.status(400).json({
                    success: false,
                    error: 'You are already signed up for this shift'
                });
            }

            // Create signup
            const signupData = {
                'Shift ID': parseInt(id),
                'Shift Title': shift.Title,
                'User Email': email,
                'User Name': name,
                'Signup Date': new Date().toISOString(),
                'Status': 'Confirmed',
                'Source': 'public'
            };

            // Add phone if provided
            if (phone && phone.trim()) {
                signupData['Phone'] = phone.trim();
            }
            
            logger.info('Creating shift signup with data:', JSON.stringify(signupData, null, 2));
            const signup = await nocodbService.create(config.nocodb.shiftSignupsSheetId, signupData);

            // Update shift volunteer count
            const newCount = (shift['Current Volunteers'] || 0) + 1;
            await nocodbService.update(config.nocodb.shiftsSheetId, id, {
                'Current Volunteers': newCount,
                'Status': newCount >= shift['Max Volunteers'] ? 'Full' : 'Open'
            });

            // Send confirmation email
            const controller = new PublicShiftsController();
            await controller.sendSignupConfirmation(email, name, shift, isNewUser, tempPassword);

            res.json({
                success: true,
                message: 'Successfully signed up! Check your email for confirmation and login details.',
                isNewUser
            });

        } catch (error) {
            logger.error('Error in public signup:', error);
            logger.error('Error details:', error.response?.data || error.message);
            res.status(500).json({
                success: false,
                error: 'Failed to complete signup. Please try again.'
            });
        }
    }

    generateTempPassword() {
        // Generate readable temporary password
        const adjectives = ['Blue', 'Green', 'Happy', 'Swift', 'Bright'];
        const nouns = ['Tiger', 'Eagle', 'River', 'Mountain', 'Star'];
        const adj = adjectives[Math.floor(Math.random() * adjectives.length)];
        const noun = nouns[Math.floor(Math.random() * nouns.length)];
        const num = Math.floor(Math.random() * 100);
        return `${adj}${noun}${num}`;
    }

    async sendSignupConfirmation(email, name, shift, isNewUser, tempPassword) {
        const baseUrl = config.isProduction ? 
            `https://map.${config.domain}` : 
            `http://localhost:${config.port}`;

        const shiftDate = new Date(shift.Date);
        
        // Prepare all variables including optional ones
        const variables = {
            APP_NAME: process.env.APP_NAME || 'CMlite Map',
            USER_NAME: name,
            USER_EMAIL: email,
            SHIFT_TITLE: shift.Title || 'Untitled Shift',
            SHIFT_DATE: shiftDate.toLocaleDateString(),
            SHIFT_TIME: `${shift['Start Time'] || ''} - ${shift['End Time'] || ''}`,
            SHIFT_LOCATION: shift.Location || 'Location TBD',
            SHIFT_DESCRIPTION: shift.Description || '', // Include even if empty
            LOGIN_URL: `${baseUrl}/login.html`,
            SHIFTS_URL: `${baseUrl}/shifts.html`,
            IS_NEW_USER: isNewUser,
            TEMP_PASSWORD: tempPassword || '',
            TIMESTAMP: new Date().toLocaleString()
        };

        // Log the variables for debugging
        logger.info('Email template variables:', JSON.stringify(variables, null, 2));

        const templateName = isNewUser ? 'public-shift-signup-new' : 'public-shift-signup-existing';
        const { html, text } = await emailTemplates.render(templateName, variables);

        return await sendEmail({
            to: email,
            subject: `Shift Signup Confirmation - ${shift.Title}`,
            text,
            html
        });
    }
}

// Create singleton instance and bind methods
const controller = new PublicShiftsController();
module.exports = {
    getPublicShifts: controller.getPublicShifts.bind(controller),
    getShiftById: controller.getShiftById.bind(controller),
    publicSignup: controller.publicSignup.bind(controller)
};