
/**
 * Spatial Operations Utility
 * Provides point-in-polygon calculations and location filtering within cut boundaries
 */

/**
 * Check if a point is inside a polygon using ray casting algorithm
 * @param {number} lat - Point latitude
 * @param {number} lng - Point longitude  
 * @param {Array} polygon - Array of [lng, lat] coordinates
 * @returns {boolean} True if point is inside polygon
 */
function isPointInPolygon(lat, lng, polygon) {
    let inside = false;
    
    for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
        const xi = polygon[i][0], yi = polygon[i][1];
        const xj = polygon[j][0], yj = polygon[j][1];
        
        if (((yi > lat) !== (yj > lat)) && 
            (lng < (xj - xi) * (lat - yi) / (yj - yi) + xi)) {
            inside = !inside;
        }
    }
    
    return inside;
}

/**
 * Check if a location is within a cut's GeoJSON polygon
 * @param {Object} location - Location object with latitude/longitude
 * @param {Object} cutGeoJson - GeoJSON polygon object
 * @returns {boolean} True if location is within cut
 */
function isLocationInCut(location, cutGeoJson) {
    // Handle different possible field names for coordinates
    const latRaw = location.latitude || location.Latitude || location.lat;
    const lngRaw = location.longitude || location.Longitude || location.lng || location.lon;
    
    if (!latRaw || !lngRaw || !cutGeoJson) {
        return false;
    }
    
    // Parse coordinates as floats since they might be strings
    const lat = parseFloat(latRaw);
    const lng = parseFloat(lngRaw);
    
    if (isNaN(lat) || isNaN(lng)) {
        return false;
    }
    
    try {
        const geojson = typeof cutGeoJson === 'string' ? JSON.parse(cutGeoJson) : cutGeoJson;
        
        if (geojson.type === 'Polygon') {
            return isPointInPolygon(lat, lng, geojson.coordinates[0]);
        } else if (geojson.type === 'MultiPolygon') {
            return geojson.coordinates.some(polygon => 
                isPointInPolygon(lat, lng, polygon[0])
            );
        }
        
        return false;
    } catch (error) {
        console.error('Error checking point in polygon:', error);
        return false;
    }
}

/**
 * Filter locations based on cut boundaries and additional criteria
 * @param {Array} locations - Array of location objects
 * @param {Object} cut - Cut object with geojson
 * @param {Object} filters - Additional filter criteria
 * @returns {Array} Filtered locations within cut
 */
function filterLocationsInCut(locations, cut, filters = {}) {
    // Try multiple possible field names for the geojson data
    const geojsonData = cut.geojson || cut.Geojson || cut.GeoJSON || cut['GeoJSON Data'] || cut.geojson_data;
    
    if (!geojsonData) {
        console.log('No geojson data found for cut:', cut.name || cut.Name || 'Unknown');
        return [];
    }
    
    // Debug: Log total locations being tested
    console.log(`Testing ${locations.length} locations against cut boundaries`);
    
    // First filter by geographic boundaries
    let filteredLocations = locations.filter(location => 
        isLocationInCut(location, geojsonData)
    );
    
    console.log(`Filtered ${locations.length} total locations down to ${filteredLocations.length} locations within cut bounds`);
    
    // Apply additional filters
    if (filters.support_level) {
        filteredLocations = filteredLocations.filter(location => {
            const supportLevel = location.support_level || location['Support Level'];
            return supportLevel === filters.support_level;
        });
    }
    
    if (filters.has_sign !== undefined) {
        filteredLocations = filteredLocations.filter(location => {
            const hasSign = location.sign || location.Sign;
            return Boolean(hasSign) === filters.has_sign;
        });
    }
    
    if (filters.sign_size) {
        filteredLocations = filteredLocations.filter(location => {
            const signSize = location.sign_size || location['Sign Size'];
            return signSize === filters.sign_size;
        });
    }
    
    if (filters.has_email !== undefined) {
        filteredLocations = filteredLocations.filter(location => {
            const email = location.email || location.Email;
            return Boolean(email) === filters.has_email;
        });
    }
    
    if (filters.has_phone !== undefined) {
        filteredLocations = filteredLocations.filter(location => {
            const phone = location.phone || location.Phone;
            return Boolean(phone) === filters.has_phone;
        });
    }
    
    return filteredLocations;
}

/**
 * Calculate statistics for locations within a cut
 * @param {Array} locations - Array of location objects within cut
 * @returns {Object} Statistics object
 */
function calculateCutStatistics(locations) {
    const stats = {
        total_locations: locations.length,
        support_levels: { '1': 0, '2': 0, '3': 0, '4': 0, 'unknown': 0 },
        lawn_signs: { has_sign: 0, no_sign: 0, unknown: 0 },
        sign_sizes: { Regular: 0, Large: 0, Unsure: 0, unknown: 0 },
        contact_info: { has_email: 0, has_phone: 0, has_both: 0, has_neither: 0 }
    };
    
    locations.forEach(location => {
        // Support level stats - handle different field names
        const supportLevel = location.support_level || location['Support Level'] || 'unknown';
        if (stats.support_levels.hasOwnProperty(supportLevel)) {
            stats.support_levels[supportLevel]++;
        } else {
            stats.support_levels.unknown++;
        }
        
        // Lawn sign stats - handle different field names
        const sign = location.sign || location.Sign;
        if (sign === true || sign === 1 || sign === 'true') {
            stats.lawn_signs.has_sign++;
        } else if (sign === false || sign === 0 || sign === 'false') {
            stats.lawn_signs.no_sign++;
        } else {
            stats.lawn_signs.unknown++;
        }
        
        // Sign size stats - handle different field names
        const signSize = location.sign_size || location['Sign Size'] || 'unknown';
        if (stats.sign_sizes.hasOwnProperty(signSize)) {
            stats.sign_sizes[signSize]++;
        } else {
            stats.sign_sizes.unknown++;
        }
        
        // Contact info stats - handle different field names
        const email = location.email || location.Email;
        const phone = location.phone || location.Phone;
        const hasEmail = Boolean(email);
        const hasPhone = Boolean(phone);
        
        if (hasEmail && hasPhone) {
            stats.contact_info.has_both++;
        } else if (hasEmail) {
            stats.contact_info.has_email++;
        } else if (hasPhone) {
            stats.contact_info.has_phone++;
        } else {
            stats.contact_info.has_neither++;
        }
    });
    
    return stats;
}

module.exports = {
    isPointInPolygon,
    isLocationInCut,
    filterLocationsInCut,
    calculateCutStatistics
};
