const nocodbService = require('../services/nocodb');
const config = require('../config');
const logger = require('../utils/logger');
const { extractId } = require('../utils/helpers');

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

            logger.info('Loading public shifts from:', config.nocodb.shiftsSheetId);

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

            let shifts = (response.list || []).filter(shift => 
                shift.Status !== 'Cancelled'
            );

            // If signups sheet is configured, calculate current volunteer counts
            if (config.nocodb.shiftSignupsSheetId) {
                try {
                    const signupsResponse = await nocodbService.getAll(config.nocodb.shiftSignupsSheetId);
                    const allSignups = signupsResponse.list || [];

                    // Update each shift with calculated volunteer count
                    shifts = shifts.map(shift => {
                        const confirmedSignups = allSignups.filter(signup => 
                            signup['Shift ID'] === shift.ID && signup.Status === 'Confirmed'
                        );
                        
                        const currentVolunteers = confirmedSignups.length;
                        const maxVolunteers = shift['Max Volunteers'] || 0;
                        
                        return {
                            ...shift,
                            'Current Volunteers': currentVolunteers,
                            'Status': currentVolunteers >= maxVolunteers ? 'Full' : 'Open'
                        };
                    });
                } catch (signupError) {
                    logger.warn('Could not load signups for volunteer count calculation:', signupError);
                }
            }

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

    // Get user's signups
    async getUserSignups(req, res) {
        try {
            const userEmail = req.session.userEmail;

            // Check if shift signups sheet is configured
            if (!config.nocodb.shiftSignupsSheetId) {
                logger.warn('Shift signups sheet not configured');
                return res.json({
                    success: true,
                    signups: []
                });
            }

            // Load all signups and filter in JavaScript
            const allSignups = await nocodbService.getAll(config.nocodb.shiftSignupsSheetId, {
                sort: '-Signup Date'
            });

            logger.info('All signups loaded:', allSignups);
            logger.info('Filtering for user:', userEmail);

            // Filter for this user's confirmed signups
            const userSignups = (allSignups.list || []).filter(signup => {
                logger.debug('Checking signup:', signup);
                // NocoDB returns fields with title case
                const email = signup['User Email'];
                const status = signup.Status;
                
                logger.debug(`Comparing: email="${email}" vs userEmail="${userEmail}", status="${status}"`);
                
                return email === userEmail && status === 'Confirmed';
            });

            logger.info('User signups found:', userSignups);

            // Transform to match expected format in frontend
            const transformedSignups = userSignups.map(signup => ({
                id: signup.ID || signup.id,
                shift_id: signup['Shift ID'],
                shift_title: signup['Shift Title'],
                user_email: signup['User Email'],
                user_name: signup['User Name'],
                signup_date: signup['Signup Date'],
                status: signup.Status
            }));

            res.json({
                success: true,
                signups: transformedSignups
            });

        } catch (error) {
            logger.error('Error fetching user signups:', error);
            // Don't fail, just return empty array
            res.json({
                success: true,
                signups: []
            });
        }
    }

    // Sign up for a shift
    async signup(req, res) {
        try {
            if (!config.nocodb.shiftsSheetId) {
                return res.status(400).json({
                    success: false,
                    error: 'Shifts sheet not configured'
                });
            }

            if (!config.nocodb.shiftSignupsSheetId) {
                return res.status(400).json({
                    success: false,
                    error: 'Shift signups sheet not configured'
                });
            }

            const { shiftId } = req.params;
            const userEmail = req.session.userEmail;
            const userName = req.session.userName || userEmail;

            logger.info(`User ${userEmail} attempting to sign up for shift ${shiftId}`);

            // Check if shift exists and is open
            const shift = await nocodbService.getById(config.nocodb.shiftsSheetId, shiftId);
            
            if (!shift || shift.Status === 'Cancelled') {
                return res.status(400).json({
                    success: false,
                    error: 'Shift not available'
                });
            }

            // Calculate current volunteers dynamically
            let currentVolunteers = 0;
            let allSignups = { list: [] }; // Initialize with empty list
            if (config.nocodb.shiftSignupsSheetId) {
                allSignups = await nocodbService.getAll(config.nocodb.shiftSignupsSheetId);
                const confirmedSignups = (allSignups.list || []).filter(signup => 
                    signup['Shift ID'] === parseInt(shiftId) && signup.Status === 'Confirmed'
                );
                currentVolunteers = confirmedSignups.length;
            }

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

            // Check if already signed up - we already have allSignups from above
            const existingSignup = (allSignups.list || []).find(signup => {
                return signup['Shift ID'] === parseInt(shiftId) && 
                       signup['User Email'] === userEmail && 
                       signup.Status === 'Confirmed';
            });

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

            // Create signup
            const signup = await nocodbService.create(config.nocodb.shiftSignupsSheetId, {
                'Shift ID': parseInt(shiftId),
                'Shift Title': shift.Title,
                'User Email': userEmail,
                'User Name': userName,
                'Signup Date': new Date().toISOString(),
                'Status': 'Confirmed'
            });

            logger.info('Created signup:', signup);

            // Update shift volunteer count with calculated value
            await nocodbService.update(config.nocodb.shiftsSheetId, shiftId, {
                'Current Volunteers': currentVolunteers + 1,
                'Status': currentVolunteers + 1 >= shift['Max Volunteers'] ? 'Full' : 'Open'
            });

            res.json({
                success: true,
                message: 'Successfully signed up for shift'
            });

        } catch (error) {
            logger.error('Error signing up for shift:', error);
            res.status(500).json({
                success: false,
                error: 'Failed to sign up for shift'
            });
        }
    }

    // Cancel shift signup
    async cancelSignup(req, res) {
        try {
            if (!config.nocodb.shiftsSheetId || !config.nocodb.shiftSignupsSheetId) {
                return res.status(400).json({
                    success: false,
                    error: 'Shifts not configured'
                });
            }

            const { shiftId } = req.params;
            const userEmail = req.session.userEmail;

            logger.info(`User ${userEmail} attempting to cancel signup for shift ${shiftId}`);

            // Find the signup
            const allSignups = await nocodbService.getAll(config.nocodb.shiftSignupsSheetId);
            const signup = (allSignups.list || []).find(s => {
                return s['Shift ID'] === parseInt(shiftId) && 
                       s['User Email'] === userEmail && 
                       s.Status === 'Confirmed';
            });

            if (!signup) {
                return res.status(404).json({
                    success: false,
                    error: 'Signup not found'
                });
            }

            // Update signup status to cancelled
            await nocodbService.update(config.nocodb.shiftSignupsSheetId, signup.ID || signup.id, {
                'Status': 'Cancelled'
            });

            // Calculate current volunteers dynamically after cancellation
            const allSignupsAfter = await nocodbService.getAll(config.nocodb.shiftSignupsSheetId);
            const confirmedSignupsAfter = (allSignupsAfter.list || []).filter(s => 
                s['Shift ID'] === parseInt(shiftId) && s.Status === 'Confirmed'
            );
            const newCount = confirmedSignupsAfter.length;

            const shift = await nocodbService.getById(config.nocodb.shiftsSheetId, shiftId);
            await nocodbService.update(config.nocodb.shiftsSheetId, shiftId, {
                'Current Volunteers': newCount,
                'Status': newCount >= shift['Max Volunteers'] ? 'Full' : 'Open'
            });

            res.json({
                success: true,
                message: 'Successfully cancelled signup'
            });

        } catch (error) {
            logger.error('Error cancelling signup:', error);
            res.status(500).json({
                success: false,
                error: 'Failed to cancel signup'
            });
        }
    }

    // Admin: Create shift
    async create(req, res) {
        try {
            const { title, description, date, startTime, endTime, location, maxVolunteers } = req.body;

            if (!title || !date || !startTime || !endTime || !location || !maxVolunteers) {
                return res.status(400).json({
                    success: false,
                    error: 'Missing required fields'
                });
            }

            const shift = await nocodbService.create(config.nocodb.shiftsSheetId, {
                Title: title,
                Description: description,
                Date: date,
                'Start Time': startTime,
                'End Time': endTime,
                Location: location,
                'Max Volunteers': parseInt(maxVolunteers),
                'Current Volunteers': 0,
                Status: 'Open',
                'Created By': req.session.userEmail,
                'Created At': new Date().toISOString(),
                'Updated At': new Date().toISOString()
            });

            res.json({
                success: true,
                shift
            });

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

    // Admin: Update shift
    async update(req, res) {
        try {
            const { id } = req.params;
            const updateData = {};

            // Map fields that can be updated
            const fieldMap = {
                title: 'Title',
                description: 'Description',
                date: 'Date',
                startTime: 'Start Time',
                endTime: 'End Time',
                location: 'Location',
                maxVolunteers: 'Max Volunteers',
                status: 'Status'
            };

            for (const [key, field] of Object.entries(fieldMap)) {
                if (req.body[key] !== undefined) {
                    updateData[field] = req.body[key];
                }
            }

            if (updateData['Max Volunteers']) {
                updateData['Max Volunteers'] = parseInt(updateData['Max Volunteers']);
            }

            updateData['Updated At'] = new Date().toISOString();

            const updated = await nocodbService.update(config.nocodb.shiftsSheetId, id, updateData);

            res.json({
                success: true,
                shift: updated
            });

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

    // Admin: Delete shift
    async delete(req, res) {
        try {
            const { id } = req.params;

            // Check if signups sheet is configured
            if (config.nocodb.shiftSignupsSheetId) {
                try {
                    // Get all signups and filter in JavaScript to avoid NocoDB query issues
                    const allSignups = await nocodbService.getAll(config.nocodb.shiftSignupsSheetId);
                    
                    // Filter for confirmed signups for this shift
                    const signupsToCancel = (allSignups.list || []).filter(signup => 
                        signup['Shift ID'] === parseInt(id) && signup.Status === 'Confirmed'
                    );

                    // Cancel each signup
                    for (const signup of signupsToCancel) {
                        await nocodbService.update(config.nocodb.shiftSignupsSheetId, signup.ID || signup.id, {
                            Status: 'Cancelled'
                        });
                    }
                    
                    logger.info(`Cancelled ${signupsToCancel.length} signups for shift ${id}`);
                } catch (signupError) {
                    logger.error('Error cancelling signups:', signupError);
                    // Continue with shift deletion even if signup cancellation fails
                }
            }

            // Delete the shift
            await nocodbService.delete(config.nocodb.shiftsSheetId, id);

            res.json({
                success: true,
                message: 'Shift deleted successfully'
            });

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

    // Admin: Get all shifts with signup details
    async getAllAdmin(req, res) {
        try {
            if (!config.nocodb.shiftsSheetId) {
                logger.error('Shifts sheet not configured');
                return res.status(500).json({
                    success: false,
                    error: 'Shifts not configured'
                });
            }

            logger.info('Loading admin shifts from:', config.nocodb.shiftsSheetId);
            
            let shifts;
            try {
                shifts = await nocodbService.getAll(config.nocodb.shiftsSheetId, {
                    sort: '-Date,-Start Time'
                });
            } catch (apiError) {
                logger.error('Error loading shifts from NocoDB:', apiError);
                // If it's a 422 error, try without sort parameters
                if (apiError.response?.status === 422) {
                    logger.warn('Retrying without sort parameters due to 422 error');
                    try {
                        shifts = await nocodbService.getAll(config.nocodb.shiftsSheetId);
                    } catch (retryError) {
                        logger.error('Retry also failed:', retryError);
                        return res.status(500).json({
                            success: false,
                            error: 'Failed to load shifts from database'
                        });
                    }
                } else {
                    throw apiError;
                }
            }

            logger.info('Loaded shifts:', shifts);

            // Only try to get signups if the signups sheet is configured
            if (config.nocodb.shiftSignupsSheetId) {
                // Get signup counts for each shift
                for (const shift of shifts.list || []) {
                    try {
                        const signups = await nocodbService.getAll(config.nocodb.shiftSignupsSheetId);
                        // Filter signups for this shift manually
                        const shiftSignups = (signups.list || []).filter(signup => 
                            signup['Shift ID'] === shift.ID && signup.Status === 'Confirmed'
                        );
                        shift.signups = shiftSignups;
                    } catch (signupError) {
                        logger.error(`Error loading signups for shift ${shift.ID}:`, signupError);
                        shift.signups = [];
                    }
                }
            } else {
                logger.warn('Shift signups sheet not configured, skipping signup data');
                // Set empty signups for all shifts
                for (const shift of shifts.list || []) {
                    shift.signups = [];
                }
            }

            res.json({
                success: true,
                shifts: shifts.list || []
            });

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

module.exports = new ShiftsController();