const nocodbService = require('../services/nocodb');
const logger = require('../utils/logger');
const config = require('../config');
const listmonkService = require('../services/listmonk');
const { 
    syncGeoFields, 
    validateCoordinates, 
    checkBounds,
    extractId 
} = require('../utils/helpers');

class LocationsController {
    async getAll(req, res) {
        try {
            const { limit, offset = 0, where } = req.query;
            
            const params = { offset };
            
            // Only add limit if explicitly provided in query
            if (limit !== undefined) {
                params.limit = limit;
            }
            
            if (where) params.where = where;
            
            logger.info('Fetching locations from NocoDB');
            
            const response = await nocodbService.getLocations(params);
            const locations = response.list || [];
            
            // Process and validate locations
            const validLocations = locations.filter(loc => {
                loc = syncGeoFields(loc);
                
                if (loc.latitude && loc.longitude) {
                    return true;
                }
                
                // Try to parse from geodata column
                if (loc.geodata && typeof loc.geodata === 'string') {
                    const parts = loc.geodata.split(';');
                    if (parts.length === 2) {
                        loc.latitude = parseFloat(parts[0]);
                        loc.longitude = parseFloat(parts[1]);
                        return !isNaN(loc.latitude) && !isNaN(loc.longitude);
                    }
                }
                
                return false;
            });
            
            logger.info(`Retrieved ${validLocations.length} valid locations out of ${locations.length} total`);
            
            // Check if user is temp user and limit data accordingly
            if (req.session?.userType === 'temp') {
                // For temp users, return limited data but include necessary fields for functionality
                const limitedLocations = validLocations.map(loc => {
                    const locationId = loc.id || loc.Id || loc.ID || loc._id;
                    return {
                        // Include ID with all possible variants for compatibility
                        id: locationId,
                        Id: locationId,
                        ID: locationId,
                        _id: locationId,
                        'Geo-Location': loc['Geo-Location'],
                        latitude: loc.latitude,
                        longitude: loc.longitude,
                        // Include display fields needed for map functionality
                        'First Name': loc['First Name'] || '',
                        'Last Name': loc['Last Name'] || '', // Include last name for display
                        'Support Level': loc['Support Level'],
                        Address: loc.Address || '',
                        'Unit Number': loc['Unit Number'] || '',
                        Notes: loc.Notes || '',
                        Sign: loc.Sign,
                        'Sign Size': loc['Sign Size'] || '',
                        // Exclude sensitive fields like Email, Phone
                    };
                });
                
                logger.info(`Returning limited data for temp user: ${limitedLocations.length} locations`);
                
                return res.json({
                    success: true,
                    count: limitedLocations.length,
                    total: response.pageInfo?.totalRows || limitedLocations.length,
                    locations: limitedLocations,
                    isLimited: true // Flag to indicate limited data
                });
            }
            
            res.json({
                success: true,
                count: validLocations.length,
                total: response.pageInfo?.totalRows || validLocations.length,
                locations: validLocations
            });
            
        } catch (error) {
            logger.error('Error fetching locations:', error.message);
            
            if (error.response) {
                res.status(error.response.status).json({
                    success: false,
                    error: 'Failed to fetch data from NocoDB',
                    details: error.response.data
                });
            } else if (error.code === 'ECONNABORTED') {
                res.status(504).json({
                    success: false,
                    error: 'Request timeout'
                });
            } else {
                res.status(500).json({
                    success: false,
                    error: 'Internal server error'
                });
            }
        }
    }
    
    async getById(req, res) {
        try {
            const location = await nocodbService.getById(
                config.nocodb.tableId,
                req.params.id
            );
            
            res.json({
                success: true,
                location
            });
            
        } catch (error) {
            logger.error(`Error fetching location ${req.params.id}:`, error.message);
            res.status(error.response?.status || 500).json({
                success: false,
                error: 'Failed to fetch location'
            });
        }
    }
    
    async create(req, res) {
        try {
            // Add debugging logs
            logger.info('Session data:', {
                authenticated: req.session.authenticated,
                userId: req.session.userId,
                userEmail: req.session.userEmail,
                isAdmin: req.session.isAdmin
            });
            
            let locationData = { ...req.body };
            locationData = syncGeoFields(locationData);
            
            const { latitude, longitude, ...additionalData } = locationData;
            
            // Validate coordinates
            const validation = validateCoordinates(latitude, longitude);
            if (!validation.valid) {
                return res.status(400).json({
                    success: false,
                    error: validation.error
                });
            }
            
            // Check bounds if configured
            if (config.map.bounds) {
                const boundsCheck = checkBounds(validation.latitude, validation.longitude);
                if (!boundsCheck.valid) {
                    return res.status(400).json({
                        success: false,
                        error: boundsCheck.error
                    });
                }
            }
            
            // Format geodata with string values to preserve precision
            const geodata = `${validation.latitude};${validation.longitude}`;
            
            // Prepare data for NocoDB - keep coordinates as strings
            const finalData = {
                geodata,
                'Geo-Location': geodata,
                latitude: validation.latitude,
                longitude: validation.longitude,
                ...additionalData,
                created_by_user: req.session.userEmail || 'anonymous'  // Add fallback
            };
            
            logger.info('Final data being sent to NocoDB:', finalData);
            
            logger.info('Creating new location:', { 
                lat: validation.latitude, 
                lng: validation.longitude,
                user: req.session.userEmail
            });
            
            const response = await nocodbService.create(
                config.nocodb.tableId,
                finalData
            );
            
            logger.info('Location created successfully:', extractId(response));
            
            // Real-time sync to Listmonk (async, don't block response)
            if (listmonkService.syncEnabled && response.Email) {
                setImmediate(async () => {
                    try {
                        const syncResult = await listmonkService.syncLocation(response);
                        if (!syncResult.success) {
                            logger.warn('Listmonk sync failed for new location', {
                                locationId: extractId(response),
                                email: response.Email,
                                error: syncResult.error
                            });
                        } else {
                            logger.debug('Location synced to Listmonk', {
                                locationId: extractId(response),
                                email: response.Email
                            });
                        }
                    } catch (error) {
                        logger.error('Listmonk sync error for new location', {
                            locationId: extractId(response),
                            error: error.message
                        });
                    }
                });
            }
            
            res.status(201).json({
                success: true,
                location: response
            });
            
        } catch (error) {
            logger.error('Error creating location:', error.message);
            
            if (error.response) {
                res.status(error.response.status).json({
                    success: false,
                    error: 'Failed to save location to NocoDB',
                    details: error.response.data
                });
            } else {
                res.status(500).json({
                    success: false,
                    error: 'Internal server error'
                });
            }
        }
    }
    
    async update(req, res) {
        try {
            const locationId = req.params.id;
            
            // Validate ID
            if (!locationId || locationId === 'undefined' || locationId === 'null') {
                return res.status(400).json({
                    success: false,
                    error: 'Invalid location ID'
                });
            }
            
            let updateData = { ...req.body };
            
            // Remove ID fields to avoid conflicts
            delete updateData.ID;
            delete updateData.Id;
            delete updateData.id;
            delete updateData._id;
            
            // Sync geo fields
            updateData = syncGeoFields(updateData);
            
            // Add update tracking
            updateData.last_updated_by_user = req.session.userEmail;  // Changed from last_updated_by
            
            logger.info(`Updating location ${locationId}`, {
                user: req.session.userEmail
            });
            
            const response = await nocodbService.update(
                config.nocodb.tableId,
                locationId,
                updateData
            );
            
            logger.info('Location updated successfully:', locationId);
            
            // Real-time sync to Listmonk (async, don't block response)
            if (listmonkService.syncEnabled && response.Email) {
                setImmediate(async () => {
                    try {
                        const syncResult = await listmonkService.syncLocation(response);
                        if (!syncResult.success) {
                            logger.warn('Listmonk sync failed for updated location', {
                                locationId: locationId,
                                email: response.Email,
                                error: syncResult.error
                            });
                        } else {
                            logger.debug('Updated location synced to Listmonk', {
                                locationId: locationId,
                                email: response.Email
                            });
                        }
                    } catch (error) {
                        logger.error('Listmonk sync error for updated location', {
                            locationId: locationId,
                            error: error.message
                        });
                    }
                });
            }
            
            res.json({
                success: true,
                location: response
            });
            
        } catch (error) {
            logger.error(`Error updating location ${req.params.id}:`, error.message);
            
            res.status(error.response?.status || 500).json({
                success: false,
                error: 'Failed to update location',
                details: error.response?.data?.message || error.message
            });
        }
    }
    
    async delete(req, res) {
        try {
            // Check if user is temp and deny delete
            if (req.session?.userType === 'temp') {
                return res.status(403).json({
                    success: false,
                    error: 'Temporary users cannot delete locations'
                });
            }
            
            const locationId = req.params.id;
            
            // Validate ID
            if (!locationId || locationId === 'undefined' || locationId === 'null') {
                return res.status(400).json({
                    success: false,
                    error: 'Invalid location ID'
                });
            }
            
            // Get location data before deletion (for Listmonk cleanup)
            let locationData = null;
            if (listmonkService.syncEnabled) {
                try {
                    const getResponse = await nocodbService.getById(config.nocodb.tableId, locationId);
                    locationData = getResponse;
                } catch (error) {
                    logger.warn('Could not fetch location data before deletion', error.message);
                }
            }
            
            await nocodbService.delete(
                config.nocodb.tableId,
                locationId
            );
            
            logger.info(`Location ${locationId} deleted by ${req.session.userEmail}`);
            
            // Remove from Listmonk (async, don't block response)
            if (listmonkService.syncEnabled && locationData && locationData.Email) {
                setImmediate(async () => {
                    try {
                        const syncResult = await listmonkService.removeSubscriber(locationData.Email);
                        if (!syncResult.success) {
                            logger.warn('Failed to remove deleted location from Listmonk', {
                                locationId: locationId,
                                email: locationData.Email,
                                error: syncResult.error
                            });
                        } else {
                            logger.debug('Deleted location removed from Listmonk', {
                                locationId: locationId,
                                email: locationData.Email
                            });
                        }
                    } catch (error) {
                        logger.error('Listmonk cleanup error for deleted location', {
                            locationId: locationId,
                            error: error.message
                        });
                    }
                });
            }
            
            res.json({
                success: true,
                message: 'Location deleted successfully'
            });
            
        } catch (error) {
            logger.error(`Error deleting location ${req.params.id}:`, error.message);
            res.status(error.response?.status || 500).json({
                success: false,
                error: 'Failed to delete location'
            });
        }
    }
}

module.exports = new LocationsController();