const express = require('express');
const router = express.Router();
const rateLimit = require('express-rate-limit');
const { reverseGeocode, forwardGeocode, forwardGeocodeSearch, getCacheStats } = require('../services/geocoding');

// Rate limiter specifically for geocoding endpoints
const geocodeLimiter = rateLimit({
    windowMs: 15 * 60 * 1000, // 15 minutes
    max: 30, // limit each IP to 30 requests per windowMs
    trustProxy: true, // Explicitly trust proxy
    keyGenerator: (req) => {
        return req.headers['cf-connecting-ip'] || 
               req.headers['x-forwarded-for']?.split(',')[0] || 
               req.ip;
    },
    message: 'Too many geocoding requests, please try again later.'
});

/**
 * Reverse geocode endpoint
 * GET /api/geocode/reverse?lat=<latitude>&lng=<longitude>
 */
router.get('/reverse', geocodeLimiter, async (req, res) => {
    try {
        const { lat, lng } = req.query;
        
        // Validate input
        if (!lat || !lng) {
            return res.status(400).json({
                success: false,
                error: 'Latitude and longitude are required'
            });
        }
        
        const latitude = parseFloat(lat);
        const longitude = parseFloat(lng);
        
        if (isNaN(latitude) || isNaN(longitude)) {
            return res.status(400).json({
                success: false,
                error: 'Invalid latitude or longitude'
            });
        }
        
        if (latitude < -90 || latitude > 90 || longitude < -180 || longitude > 180) {
            return res.status(400).json({
                success: false,
                error: 'Coordinates out of range'
            });
        }
        
        // Perform reverse geocoding
        const result = await reverseGeocode(latitude, longitude);
        
        res.json({
            success: true,
            data: result
        });
        
    } catch (error) {
        console.error('Reverse geocoding error:', error);
        
        const statusCode = error.message.includes('Rate limit') ? 429 : 500;
        
        res.status(statusCode).json({
            success: false,
            error: error.message
        });
    }
});

/**
 * Forward geocode endpoint
 * GET /api/geocode/forward?address=<address>
 */
router.get('/forward', geocodeLimiter, async (req, res) => {
    try {
        const { address } = req.query;
        
        // Validate input
        if (!address || address.trim().length === 0) {
            return res.status(400).json({
                success: false,
                error: 'Address is required'
            });
        }
        
        // Perform forward geocoding
        const result = await forwardGeocode(address);
        
        res.json({
            success: true,
            data: result
        });
        
    } catch (error) {
        console.error('Forward geocoding error:', error);
        
        const statusCode = error.message.includes('Rate limit') ? 429 : 500;
        
        res.status(statusCode).json({
            success: false,
            error: error.message
        });
    }
});

/**
 * Forward geocode search endpoint (returns multiple results)
 * GET /api/geocode/search?query=<address>&limit=<number>
 */
router.get('/search', geocodeLimiter, async (req, res) => {
    try {
        const { query, limit } = req.query;
        
        // Validate input
        if (!query || query.trim().length === 0) {
            return res.status(400).json({
                success: false,
                error: 'Search query is required'
            });
        }
        
        // Minimum search length
        if (query.trim().length < 2) {
            return res.json({
                success: true,
                data: []
            });
        }
        
        const searchLimit = parseInt(limit) || 5;
        
        if (searchLimit < 1 || searchLimit > 10) {
            return res.status(400).json({
                success: false,
                error: 'Limit must be between 1 and 10'
            });
        }
        
        // Perform forward geocoding search
        const results = await forwardGeocodeSearch(query, searchLimit);
        
        res.json({
            success: true,
            data: results,
            query: query,
            count: results.length
        });
        
    } catch (error) {
        console.error('Forward geocoding search error:', error);
        
        const statusCode = error.message.includes('Rate limit') ? 429 : 500;
        
        res.status(statusCode).json({
            success: false,
            error: error.message
        });
    }
});

/**
 * Get geocoding provider status
 * GET /api/geocode/provider-status
 */
router.get('/provider-status', (req, res) => {
    try {
        const providers = [
            {
                name: 'Mapbox',
                available: !!(process.env.MAPBOX_ACCESS_TOKEN || process.env.MAPBOX_API_KEY),
                type: 'premium'
            },
            {
                name: 'Nominatim',
                available: true,
                type: 'free'
            },
            {
                name: 'Photon',
                available: true,
                type: 'free'
            },
            {
                name: 'LocationIQ',
                available: !!process.env.LOCATIONIQ_API_KEY,
                type: 'premium'
            },
            {
                name: 'ArcGIS',
                available: true,
                type: 'free'
            }
        ];

        res.json({
            success: true,
            providers: providers,
            hasPremium: providers.some(p => p.available && p.type === 'premium')
        });
    } catch (error) {
        console.error('Error checking provider status:', error);
        res.status(500).json({
            success: false,
            error: 'Failed to check provider status'
        });
    }
});

/**
 * Get geocoding cache statistics (admin endpoint)
 * GET /api/geocode/cache/stats
 */
router.get('/cache/stats', (req, res) => {
    res.json({
        success: true,
        data: getCacheStats()
    });
});

module.exports = router;
