// Aladin Astronomical Extension
// Provides moon position, moon avoidance circles, and horizon line functionality

/**
 * Calculates angular distance between two celestial coordinates
 * @param {number} ra1 - First RA in degrees
 * @param {number} dec1 - First Dec in degrees
 * @param {number} ra2 - Second RA in degrees
 * @param {number} dec2 - Second Dec in degrees
 * @returns {number} Angular distance in degrees
 */
function calculateAngularDistance(ra1, dec1, ra2, dec2) {
    const toRad = Math.PI / 180;
    const ra1Rad = ra1 * toRad;
    const dec1Rad = dec1 * toRad;
    const ra2Rad = ra2 * toRad;
    const dec2Rad = dec2 * toRad;
    
    const deltaRa = ra2Rad - ra1Rad;
    const distance = Math.acos(
        Math.sin(dec1Rad) * Math.sin(dec2Rad) + 
        Math.cos(dec1Rad) * Math.cos(dec2Rad) * Math.cos(deltaRa)
    );
    
    return distance / toRad; // Convert back to degrees
}

/**
 * Gets moon phase symbol based on illumination
 * @param {number} illumination - Illumination fraction (0-1)
 * @returns {string} Moon phase symbol
 */
function getMoonPhaseSymbol(illumination) {
    if (illumination < 0.1) return 'New'; // New Moon
    if (illumination < 0.3) return 'Crescent'; // Waxing Crescent
    if (illumination < 0.7) return 'Quarter'; // First Quarter
    if (illumination < 0.9) return 'Gibbous'; // Waxing Gibbous
    return 'Full'; // Full Moon
}

/**
 * Extends the Aladin instance with astronomical functionality
 * @param {Object} aladinInstance - The Aladin instance to extend
 */
function extendAladinWithAstronomical(aladinInstance) {
    if (!aladinInstance) {
        console.error('Cannot extend null Aladin instance with astronomical functionality');
        return;
    }
    
    // Add astronomical-specific properties
    aladinInstance.astronomicalOverlays = {
        moonMarker: null,
        moonAvoidanceCircles: [],
        horizonLine: null
    };

    // Set up event listeners for automatic updates on zoom/pan changes
    /*
    aladinInstance.aladin.on('zoomChanged', function() {
        if (aladinInstance.astronomicalOverlays.moonMarker) {
            aladinInstance.updateMoonPosition();
        }
    });

    aladinInstance.aladin.on('positionChanged', function() {
        if (aladinInstance.astronomicalOverlays.moonMarker) {
            aladinInstance.updateMoonPosition();
        }
    });
    */

    /**
     * Adds a moon marker to the sky view
     * @param {number} ra - Right Ascension in degrees
     * @param {number} dec - Declination in degrees
     * @param {number} illumination - Moon illumination fraction (0-1)
     */
    aladinInstance.addMoonMarker = function(ra, dec, illumination) {
        try {
            // Clear existing moon marker
            this.clearMoonMarker();
            
            const container = this.aladin.aladinDiv;
            if (!container) {
                console.error('Aladin container not found');
                return;
            }

            // Create moon marker container
            const moonElement = document.createElement('div');
            moonElement.id = 'moon-marker';
            moonElement.className = 'astronomical-marker moon-marker';
            moonElement.style.cssText = `
                position: absolute;
                pointer-events: none;
                z-index: 15;
                transform: translate(-50%, -50%);
                display: flex;
                flex-direction: column;
                align-items: center;
            `;
            
            // Add moon phase icon
            const phaseIcon = document.createElement('div');
            phaseIcon.className = 'moon-phase-icon';
            phaseIcon.style.cssText = `
                font-size: 28px;
                line-height: 1;
                filter: grayscale(100%);
                margin-bottom: 3px;
            `;
            phaseIcon.textContent = getMoonPhaseSymbol(illumination);
            
            // Add percentage text below
            const phaseText = document.createElement('div');
            phaseText.className = 'moon-phase-label';
            phaseText.style.cssText = `
                color: white;
                font-size: 14px;
                font-weight: bold;
                text-shadow: 1px 1px 2px rgba(0,0,0,0.8);
                white-space: nowrap;
                text-align: center;
            `;
            phaseText.textContent = `${(illumination * 100).toFixed(0)}%`;
            
            moonElement.appendChild(phaseIcon);
            moonElement.appendChild(phaseText);
            container.appendChild(moonElement);
            
            // Store moon data
            this.astronomicalOverlays.moonMarker = {
                element: moonElement,
                ra: ra,
                dec: dec,
                illumination: illumination
            };
            
            // Update position
            this.updateMoonPosition();
            
        } catch (error) {
            console.error('Error adding moon marker:', error);
        }
    };

    /**
     * Updates moon marker position based on current view
     * This only updates the visual position, not the RA/Dec coordinates
     */
    aladinInstance.updateMoonPosition = function() {
        try {
            if (!this.astronomicalOverlays.moonMarker) return;
            
            const moonData = this.astronomicalOverlays.moonMarker;
            const element = moonData.element;
            
            if (!element) return;
            
            // Use Aladin's proper coordinate transformation
            // This handles spherical projection correctly
            const pixelCoords = this.aladin.world2pix(moonData.ra * 15, moonData.dec);
            
            if (!pixelCoords || pixelCoords.length < 2) {
                // Moon is outside current view or projection failed
                element.style.display = 'none';
                return;
            }
            
            const [moonX, moonY] = pixelCoords;
            
            // Check if moon is within visible bounds
            const containerWidth = this.aladin.aladinDiv.offsetWidth;
            const containerHeight = this.aladin.aladinDiv.offsetHeight;
            
            if (moonX < -50 || moonX > containerWidth + 50 || 
                moonY < -50 || moonY > containerHeight + 50) {
                // Moon is outside visible area (with margin)
                element.style.display = 'none';
                return;
            }
            
            // Position the moon marker
            element.style.display = 'block';
            element.style.left = `${moonX}px`;
            element.style.top = `${moonY}px`;
            
        } catch (error) {
            console.error('Error updating moon position:', error);
            // Hide moon marker on error
            if (this.astronomicalOverlays.moonMarker && this.astronomicalOverlays.moonMarker.element) {
                this.astronomicalOverlays.moonMarker.element.style.display = 'none';
            }
        }
    };

    /**
     * Updates moon marker with new coordinates and illumination
     * This should be called when time changes to update moon's actual position
     */
    aladinInstance.updateMoonData = function(ra, dec, illumination) {
        try {
            if (!this.astronomicalOverlays.moonMarker) return;
            
            const moonData = this.astronomicalOverlays.moonMarker;
            
            // Update stored coordinates and illumination
            moonData.ra = ra;
            moonData.dec = dec;
            moonData.illumination = illumination;
            
            // Update phase icon and percentage text
            const phaseIcon = moonData.element.querySelector('.moon-phase-icon');
            const phaseText = moonData.element.querySelector('.moon-phase-label');
            if (phaseIcon) {
                phaseIcon.textContent = getMoonPhaseSymbol(illumination);
            }
            if (phaseText) {
                phaseText.textContent = `${(illumination * 100).toFixed(0)}%`;
            }
            
            // Update visual position
            this.updateMoonPosition();
            
        } catch (error) {
            console.error('Error updating moon data:', error);
        }
    };
    
    /**
     * Adds moon avoidance circles for filter profiles using Aladin polylines
     * @param {Array} circleData - Array of {points, color, filterName, distance} objects with pre-calculated RA/Dec points
     */
    aladinInstance.addMoonAvoidanceCircles = function(circleData) {
        try {
            // Clear existing circles
            this.clearMoonAvoidanceCircles();
            
            // Always use Aladin polyline approach
            this.addMoonAvoidanceCirclesAladin(circleData);
            
        } catch (error) {
            console.error('Error adding moon avoidance circles:', error);
        }
    };

    /**
     * Adds moon avoidance circles using Aladin's polyline with pre-calculated points
     * @param {Array} circleData - Array of {points, color, filterName, distance} objects with pre-calculated RA/Dec points
     */
    aladinInstance.addMoonAvoidanceCirclesAladin = function(circleData) {
        try {
            circleData.forEach(({points, color, filterName, distance}) => {
                // Create a graphic overlay for this circle
                const overlay = A.graphicOverlay({
                    color: color,
                    lineWidth: 2,
                    lineDash: [5, 5]
                });
                
                // Add the overlay to Aladin first
                this.aladin.addOverlay(overlay);
                
                // Split circle into X divisions to avoid Aladin hiding entire polylines
                const quadrants = this.splitCircleIntoDivisions(points, 12);
                const polylines = [];
                
                quadrants.forEach(quadrant => {
                    if (quadrant.length >= 2) {
                        const polyline = A.polyline(quadrant, {
                            color: color,
                            lineWidth: 2,
                            lineDash: [5, 5]
                        });
                        
                        overlay.add(polyline);
                        polylines.push(polyline);
                    }
                });
                
                // Store circle data
                this.astronomicalOverlays.moonAvoidanceCircles.push({
                    polylines: polylines,
                    overlay: overlay,
                    distance: distance,
                    color: color,
                    filterName: filterName,
                    type: 'aladin'
                });
            });
            
                        
        } catch (error) {
            console.error('Error adding Aladin moon avoidance circles:', error);
        }
    };

    /**
     * Splits circle points into 4 equal quadrants to prevent Aladin from hiding entire polylines
     * @param {Array} points - Array of [ra, dec] coordinate pairs
     * @returns {Array} Array of 4 quadrants, each containing 1/4 of the points plus overlap
     */
    aladinInstance.splitCircleIntoDivisions = function(points, divisions) {
        if (!points || points.length < 8) return [points]; // Need at least 8 points for 4 quadrants
        
        const quadrants = [];
        const pointsPerQuadrant = Math.floor(points.length / divisions);
        const overlap = 2; // Increase overlap for better continuity
        
        for (let i = 0; i < divisions; i++) {
            const startIndex = i * pointsPerQuadrant;
            let endIndex;
            
            if (i === (divisions - 1)) {
                // Last quadrant: go to end and wrap around to include first point for closure
                endIndex = points.length + overlap;
            } else {
                endIndex = (i + 1) * pointsPerQuadrant + overlap;
            }
            
            // Extract points for this quadrant
            let quadrantPoints = [];
            
            for (let j = startIndex; j < endIndex; j++) {
                const index = j % points.length; // Handle wraparound
                quadrantPoints.push(points[index]);
            }
            
            // For the last quadrant, ensure it connects back to the first point
            if (i === (divisions - 1) && quadrantPoints.length > 0) {
                // Add the first point at the end to close the circle
                const firstPoint = points[0];
                const lastPoint = quadrantPoints[quadrantPoints.length - 1];
                
                // Only add if it's not already the same point
                if (firstPoint[0] !== lastPoint[0] || firstPoint[1] !== lastPoint[1]) {
                    quadrantPoints.push(firstPoint);
                }
            }
            
            // Ensure we have at least 2 points for a valid polyline
            if (quadrantPoints.length >= 2) {
                quadrants.push(quadrantPoints);
            }
        }
        
        return quadrants;
    };

    /**
     * Adds custom horizon line for the observatory using Aladin polylines
     * @param {Array} horizonPoints - Array of {ra, dec} points defining the horizon
     */
    aladinInstance.addHorizonLine = function(horizonPoints) {
        try {
            // Clear existing horizon line
            this.clearHorizonLine();
            
            if (!horizonPoints || horizonPoints.length < 2) return;
            
            // Convert points to [ra, dec] format if needed
            const points = horizonPoints.map(point => [point.ra, point.dec - 0.05]);
            
            // Create graphic overlay for horizon line
            const horizonOverlay = A.graphicOverlay({
                color: '#8B4513',
                lineWidth: 3,
                lineDash: [8, 4]
            });
            
            // Add the overlay to Aladin
            this.aladin.addOverlay(horizonOverlay);
            
            // Split horizon into segments to avoid hiding when parts are behind sphere
            const segments = this.splitHorizonIntoSegments(points, 12);
            const polylines = [];
            
            segments.forEach(segment => {
                if (segment.length >= 2) {
                    const polyline = A.polyline(segment, {
                        color: '#8B4513',
                        lineWidth: 3,
                        lineDash: [8, 4],
                        fill: true,
                        fillColor: '#8B4513'                      
                    });
                    
                    horizonOverlay.add(polyline);
                    polylines.push(polyline);
                }
            });
            
            // Add visual indicators for above/below horizon
            this.addHorizonIndicators(horizonOverlay, points);
            
            // Store horizon data
            this.astronomicalOverlays.horizonLine = {
                overlay: horizonOverlay,
                polylines: polylines,
                points: points,
                type: 'aladin'
            };
            
                        
        } catch (error) {
            console.error('Error adding horizon line:', error);
        }
    };

    /**
     * Splits horizon points into segments to prevent Aladin from hiding entire polylines
     * @param {Array} points - Array of [ra, dec] coordinate pairs
     * @returns {Array} Array of segments, each containing continuous points
     */
    aladinInstance.splitHorizonIntoSegments = function(points, divisions) {
        if (!points || points.length < 4) return [points];
        
        const segments = [];
        const pointsPerSegment = Math.max(4, Math.floor(points.length / divisions)); // Create ~6 segments
        const overlap = 1; // Add overlap for continuity
        
        for (let i = 0; i < points.length; i += pointsPerSegment - overlap) {
            const endIndex = Math.min(i + pointsPerSegment, points.length);
            const segment = points.slice(i, endIndex);
            
            if (segment.length >= 2) {
                segments.push(segment);
            }
            
            if (endIndex >= points.length) break;
        }
        
        return segments;
    };

    /**
     * Adds a second horizon line 0.2 degrees higher in green to show observable area
     * @param {Object} overlay - The Aladin graphic overlay
     * @param {Array} points - Array of [ra, dec] horizon points
     */
    aladinInstance.addHorizonIndicators = function(overlay, points) {
        try {
            // Create observable horizon line (0.2 degrees higher in green)
            this.createObservableHorizonLine(overlay, points);
            
        } catch (error) {
            console.error('Error adding horizon indicators:', error);
        }
    };

    /**
     * Creates a second horizon line 0.2 degrees higher in green to show the observable area
     * @param {Object} overlay - The Aladin graphic overlay  
     * @param {Array} horizonPoints - Array of [ra, dec] horizon points
     */
    aladinInstance.createObservableHorizonLine = function(overlay, horizonPoints) {
        try {
            // Create points for the observable horizon line (0.2 degrees higher)
            const observablePoints = horizonPoints.map(point => [
                point[0], // Same RA
                point[1] + 0.05 // Declination
            ]);
            
            // Split observable horizon into segments to avoid hiding when parts are behind sphere
            const segments = this.splitHorizonIntoSegments(observablePoints, 12);
            const polylines = [];
            
            segments.forEach(segment => {
                if (segment.length >= 2) {
                    const polyline = A.polyline(segment, {
                        color: '#4CAF50',      // Green color for observable area
                        lineWidth: 2,          // Slightly thinner than main horizon
                        lineDash: [4, 2]       // Shorter dashes to differentiate
                    });
                    
                    overlay.add(polyline);
                    polylines.push(polyline);
                }
            });
            
                        
        } catch (error) {
            console.error('Error creating observable horizon line:', error);
        }
    };

/**
 * Selects strategic points along horizon for placing labels
 * @param {Array} points - Array of [ra, dec] horizon points
 * @returns {Array} Array of {point, direction} objects
 */
aladinInstance.selectHorizonLabelPoints = function(points) {
    if (!points || points.length < 4) return [];
    
    const labelPoints = [];
    const numLabels = Math.min(4, Math.floor(points.length / 8)); // Up to 4 labels
    
    for (let i = 0; i < numLabels; i++) {
        const index = Math.floor((i * points.length) / numLabels);
        const point = points[index];
        
        // Alternate between above and below indicators
        const direction = i % 2 === 0 ? 'above' : 'below';
        
        labelPoints.push({ point, direction });
    }
    
    return labelPoints;
};

    /**
     * Clears the moon marker
     */
    aladinInstance.clearMoonMarker = function() {
        try {
            if (this.astronomicalOverlays.moonMarker && this.astronomicalOverlays.moonMarker.element) {
                this.astronomicalOverlays.moonMarker.element.remove();
                this.astronomicalOverlays.moonMarker = null;
            }
        } catch (error) {
            console.error('Error clearing moon marker:', error);
        }
    };

    /**
     * Clears all moon avoidance circles
     */
    aladinInstance.clearMoonAvoidanceCircles = function() {
        try {
            // Keep track of overlays to remove (avoid duplicates)
            const overlaysToRemove = new Set();
            
            this.astronomicalOverlays.moonAvoidanceCircles.forEach(circle => {
                if (circle.overlay) {
                    // Remove Aladin graphic overlay
                    overlaysToRemove.add(circle.overlay);
                }
            });
            
            // Remove unique overlays
            overlaysToRemove.forEach(overlay => {
                this.aladin.removeOverlay(overlay);
            });
            
            this.astronomicalOverlays.moonAvoidanceCircles = [];
        } catch (error) {
            console.error('Error clearing moon avoidance circles:', error);
        }
    };

    /**
     * Clears the horizon line
     */
    aladinInstance.clearHorizonLine = function() {
        try {
            if (this.astronomicalOverlays.horizonLine && this.astronomicalOverlays.horizonLine.overlay) {
                this.aladin.removeOverlay(this.astronomicalOverlays.horizonLine.overlay);
                this.astronomicalOverlays.horizonLine = null;
            }
        } catch (error) {
            console.error('Error clearing horizon line:', error);
        }
    };

    /**
     * Updates all astronomical overlays when view changes
     */
    aladinInstance.updateAstronomicalOverlays = function() {
        try {
            this.updateMoonPosition();
        } catch (error) {
            console.error('Error updating astronomical overlays:', error);
        }
    };
    
    /**
     * Toggles visibility of astronomical overlays
     * @param {string} overlayType - Type of overlay ('moon', 'horizon', 'circles')
     */
    aladinInstance.toggleAstronomicalOverlay = function(overlayType) {
        try {
            switch (overlayType) {
                case 'moon':
                    if (this.astronomicalOverlays.moonMarker && this.astronomicalOverlays.moonMarker.element) {
                        const element = this.astronomicalOverlays.moonMarker.element;
                        element.style.display = element.style.display === 'none' ? 'block' : 'none';
                    }
                    break;
                case 'horizon':
                    if (this.astronomicalOverlays.horizonLine && this.astronomicalOverlays.horizonLine.container) {
                        const container = this.astronomicalOverlays.horizonLine.container;
                        container.style.display = container.style.display === 'none' ? 'block' : 'none';
                    }
                    break;
                case 'circles':
                    this.astronomicalOverlays.moonAvoidanceCircles.forEach(circle => {
                        if (circle.element) {
                            circle.element.style.display = circle.element.style.display === 'none' ? 'block' : 'none';
                        }
                    });
                    break;
            }
        } catch (error) {
            console.error('Error toggling astronomical overlay:', error);
        }
    };
    
    // Event listeners are now handled centrally in aladin.js
    // The main positionChangedHandler will call updateAstronomicalOverlays() when needed
}

// Global functions for Blazor integration
window.addMoonMarker = function(ra, dec, illumination) {
        if (window.aladinInstance && window.aladinInstance.addMoonMarker) {
        window.aladinInstance.addMoonMarker(ra, dec, illumination);
    } else {
        console.error('Aladin instance or addMoonMarker method not available');
    }
};

window.updateMoonData = function(ra, dec, illumination) {
        if (window.aladinInstance && window.aladinInstance.updateMoonData) {
        window.aladinInstance.updateMoonData(ra, dec, illumination);
    } else {
        console.error('Aladin instance or updateMoonData method not available');
    }
};

window.addMoonAvoidanceCircles = function(avoidanceDistances) {
        if (window.aladinInstance && window.aladinInstance.addMoonAvoidanceCircles) {
        window.aladinInstance.addMoonAvoidanceCircles(avoidanceDistances);
    } else {
        console.error('Aladin instance or addMoonAvoidanceCircles method not available');
    }
};

window.addHorizonLine = function(horizonPoints) {
        if (window.aladinInstance && window.aladinInstance.addHorizonLine) {
        window.aladinInstance.addHorizonLine(horizonPoints);
    } else {
        console.error('Aladin instance or addHorizonLine method not available');
    }
};

window.clearMoonMarker = function() {
        if (window.aladinInstance && window.aladinInstance.clearMoonMarker) {
        window.aladinInstance.clearMoonMarker();
    } else {
        console.error('Aladin instance or clearMoonMarker method not available');
    }
};

window.clearMoonAvoidanceCircles = function() {
        if (window.aladinInstance && window.aladinInstance.clearMoonAvoidanceCircles) {
        window.aladinInstance.clearMoonAvoidanceCircles();
    } else {
        console.error('Aladin instance or clearMoonAvoidanceCircles method not available');
    }
};

window.clearHorizonLine = function() {
        if (window.aladinInstance && window.aladinInstance.clearHorizonLine) {
        window.aladinInstance.clearHorizonLine();
    } else {
        console.error('Aladin instance or clearHorizonLine method not available');
    }
};

window.toggleAstronomicalOverlay = function(overlayType) {
        if (window.aladinInstance && window.aladinInstance.toggleAstronomicalOverlay) {
        window.aladinInstance.toggleAstronomicalOverlay(overlayType);
    } else {
        console.error('Aladin instance or toggleAstronomicalOverlay method not available');
    }
};

// Make extendAladinWithAstronomical globally available
window.extendAladinWithAstronomical = extendAladinWithAstronomical;

// Export functions for module use
if (typeof module !== 'undefined' && module.exports) {
    module.exports = {
        calculateAngularDistance,
        getMoonPhaseSymbol,
        extendAladinWithAstronomical
    };
}
