// Aladin Lite viewer initialization and management
export async function initializeAladin(pContainerId, dotNetHelper, options = {}) {
    // Default options
    const defaults = {
        target: "10.6847 41.2692", // Default to M31
        fov: 2.0, // 1 degree FOV
        survey: "P/DSS2/color",
        showFov: false,
        fovWidth: 0,
        fovHeight: 0,
        fovRotation: 0
    };


    const settings = { ...defaults, ...options };

    const containerId = pContainerId;

    // Function to load a script
    const loadScript = (src) => {
        return new Promise((resolve, reject) => {
            const script = document.createElement('script');
            script.src = src;
            script.onload = () => resolve();
            script.onerror = () => reject(new Error(`Failed to load script: ${src}`));
            document.head.appendChild(script);
        });
    };

    try {
        // Load Aladin Lite script if not already loaded
        if (!window.A) {
            try {
                await loadScript('https://aladin.cds.unistra.fr/AladinLite/api/v3/latest/aladin.js');
            } catch (e) {
                console.warn('Failed to load Aladin from official CDN, trying alternative source');
                try {
                    await loadScript('https://unpkg.com/aladin-lite@2.8.13/dist/aladin.js');
                } catch (e2) {
                    console.error('All script loading attempts failed');
                    throw new Error('Could not load Aladin Lite from any source');
                }
            }

            // Wait for A.aladin to be available
            await new Promise((resolve, reject) => {
                const startTime = Date.now();
                const checkAladin = () => {
                    if (window.A && window.A.aladin) {
                        resolve();
                    } else if (Date.now() - startTime > 10000) { // 10 second timeout
                        reject(new Error('Timeout waiting for Aladin Lite to load'));
                    } else {
                        setTimeout(checkAladin, 50);
                    }
                };
                checkAladin();
            });
        }

        // Check if container element exists before initializing
        const containerElement = document.getElementById(containerId);
        if (!containerElement) {
            throw new Error(`Container element with ID '${containerId}' not found`);
        }

        // Initialize Aladin Lite
        const aladin = A.aladin(`#${containerId}`, {
            survey: settings.survey, // set initial image survey
            projection: 'SIN', // set a projection
            fov: settings.fov[0],
            target: settings.target,
            cooFrame: 'ICRS', // set galactic frame
            showCooGrid: false, // set the grid
            showReticle: true,
            showFrame: true,
            showContextMenu: true,
            showGotoControl: true,
            showSimbadPointerControl: true,
            showZoomControl: true,
            showLayersControl: true,
            showFullscreenControl: false
        });

        // Set position angle to 0 at the bottom (like Telescopius)
        aladin.setRotation(0);

        // Ensure ICRS coordinate system is properly set
        aladin.setFrame('ICRS');

        // Update the cleanup function to remove these event listeners
        window.cleanupAladin = function () {
            if (aladin && aladin.view && aladin.view.imageCanvas) {
                aladin.view.imageCanvas.removeEventListener('click', clickHandler);
            }
        };

        // Function to update coordinates display
        const updateCoordinates = () => {
            try {
                // Get current RA/Dec and FOV directly from Aladin instance
                const position = aladin.getRaDec();
                const fov = aladin.getFov(); // This returns [width, height]
                const fovWidth = fov[0];     // Get the width (first element)     

                if (position && position.length >= 2) {
                    const [ra, dec] = position;

                    // Update the UI elements directly
                    updateCoordinateDisplay(ra, dec, fov);

                    // Also update via DotNet if needed
                    if (dotNetHelper) {
                        dotNetHelper.invokeMethodAsync('UpdateCoordinates', {
                            ra: ra,
                            dec: dec,
                            fov: fovWidth
                        }).catch(e => console.error('Error updating coordinates:', e));
                    }
                }
            } catch (e) {
                console.error('Error in coordinate update:', e);
            }
        };

        // Add debounce function to prevent excessive updates
        function debounce(func, wait) {
            let timeout;
            return function () {
                const context = this;
                const args = arguments;
                clearTimeout(timeout);
                timeout = setTimeout(() => {
                    func.apply(context, args);

                }, wait);
            };
        }

        // Debounced version of updateCoordinates
        const debouncedUpdate = debounce(updateCoordinates, 50);


        const positionChangedHandler = () => {
            // Ensure rotation is always 0 (north up, east left)
            if (aladinInstance.aladin.getRotation && aladinInstance.aladin.getRotation() !== 0) {
                aladinInstance.aladin.setRotation(0);
            }
            // Update all marker label positions
            aladinInstance.updateAllMarkerLabels();
            
            // Update DSO overlay positions
            aladinInstance.updateAllDSOPositions();

            // Dispatch to extension modules
            if (aladinInstance.updateMosaicPanelPositions && aladinInstance.mosaicOverlays?.length > 0) {
                aladinInstance.updateMosaicPanelPositions();
            }
            if (aladinInstance.updateAstronomicalOverlays) {
                aladinInstance.updateAstronomicalOverlays();
            }
        };

        // Set up centralized event listeners for view changes
        aladin.on('positionChanged', positionChangedHandler);
        aladin.on('zoomChanged', positionChangedHandler);

        // Add specific FOV change handler to ensure overlays update
        aladin.on('fovChanged', () => {
            if (aladinInstance.fovOverlays && aladinInstance.fovOverlays.length > 0) {
                aladinInstance.updateAllFovOverlayPositions();
            }
            // Also dispatch FOV changes to extensions
            if (aladinInstance.updateMosaicPanelPositions && aladinInstance.mosaicOverlays?.length > 0) {
                aladinInstance.updateMosaicPanelPositions();
            }
            if (aladinInstance.updateAstronomicalOverlays) {
                aladinInstance.updateAstronomicalOverlays();
            }
        });

        // define function triggered when an object is clicked
        var objClicked;
        aladin.on('objectClicked', (object) => {
            if (object) {
                // Center the object in the view
                aladin.gotoRaDec(object.ra, object.dec);

                // If we have a objId (DSO identifier), use it to select in SkyAtlas
                if (object.data.objId && dotNetHelper) {
                    // Call the SelectDSO method in the Blazor component
                    dotNetHelper.invokeMethodAsync('SelectDSO', object.data.objId)
                        .catch(err => console.error('Error selecting DSO:', err));
                }

                // Highlight the selected object
                if (objClicked) {
                    objClicked.deselect();
                }
                objClicked = object;
                object.select();
            } else if (objClicked) {
                objClicked.deselect();
                objClicked = null;
            }
        });

        // Store the Aladin instance
        const aladinInstance = {
            aladin: aladin,
            dotNetHelper: dotNetHelper, // Store the dotNetHelper reference
            markers: [],
            markerCatalog: null,
            fovSettings: null,
            fovOverlays: [], // Array to store multiple FOV overlays
            fovOverlayElements: new Map(), // Map overlay ID to DOM elements
            positionChangedListener: positionChangedHandler,
            showMarkerLabels: true, // Default to showing labels

            hoveredLabelBounds: null,
            lastHoveredLabelBounds: null,

            // Set whether to show marker labels
            setShowMarkerLabels: function (show) {
                this.showMarkerLabels = !!show;
                // Update all existing markers
                this.markers.forEach(marker => {
                    if (marker && marker.setLabel) {
                        // Toggle label visibility
                        const currentLabel = marker.getLabel();
                        if (currentLabel) {
                            marker.setLabel({
                                ...currentLabel,
                                visible: this.showMarkerLabels
                            });
                        }
                    }
                });
            },

            isPointInLabel: function (x, y) {
                // Check if point is within any label bounds
                for (const label of this.labelPositions || []) {
                    if (x >= label.x &&
                        x <= label.x + label.width &&
                        y >= label.y &&
                        y <= label.y + label.height) {
                        return label.source;
                    }
                }
                return null;
            },

            addAladinButton: function (options) {
                if (!window.A || !this.aladin) {
                    console.error('Aladin not available or instance not provided');
                    return null;
                }

                const config = {
                    content: options.content || 'Button',
                    classList: options.classList || [],
                    tooltip: options.tooltip || options.title || null,
                    position: options.position || 'top-right',
                    onClick: options.onClick || null,
                    buttonId: options.xButtonId || null
                };

                try {
                    let btn = A.button({
                        content: config.content,
                        classList: config.classList,
                        action: () => {
                            if (config.onClick && config.onClick.invokeMethodAsync) {
                                // .NET callback - determine method based on button ID
                                let methodName = 'CycleFovAsync'; // default

                                switch (config.buttonId) {
                                    case 'xFOVinput':
                                        methodName = 'ShowFovInputAsync';
                                        break;
                                    case 'xDateTimeBtn':
                                        methodName = 'ShowDateTimePopupAsync';
                                        break;
                                    case 'xStretchToggle':
                                        methodName = 'ToggleStretchAsync';
                                        break;
                                    case 'xFOVswitch':
                                        methodName = 'CycleFovAsync';
                                        break;
                                    default:
                                        methodName = 'CycleFovAsync';
                                        break;
                                }

                                                                config.onClick.invokeMethodAsync(methodName).catch(error => {
                                    console.error('Error invoking method:', methodName, error);
                                });
                            } else {
                                                            }
                        }
                    });

                    this.aladin.addUI(btn);

                    // Store button reference for later updates if it has an ID
                    if (config.buttonId) {
                        if (!this.buttons) {
                            this.buttons = new Map();
                        }
                        this.buttons.set(config.buttonId, btn);
                                            }

                    // Apply custom positioning
                    setTimeout(() => {
                        const btnElement = btn.el;
                        if (btnElement) {
                            btnElement.style.position = 'absolute';

                            switch (config.position) {
                                case 'bottom-left':
                                    btnElement.style.bottom = '66px';
                                    btnElement.style.left = '4px';
                                    btnElement.style.top = 'auto';
                                    btnElement.style.right = 'auto';
                                    break;
                                case 'bottom-right':
                                    btnElement.style.bottom = '10px';
                                    btnElement.style.right = '10px';
                                    btnElement.style.top = 'auto';
                                    btnElement.style.left = 'auto';
                                    break;
                                case 'top-left':
                                    btnElement.style.top = '87px';
                                    btnElement.style.left = '4px';
                                    btnElement.style.bottom = 'auto';
                                    btnElement.style.right = 'auto';
                                    break;
                                default: // top-right
                                    btnElement.style.top = '10px';
                                    btnElement.style.right = '10px';
                                    btnElement.style.bottom = 'auto';
                                    btnElement.style.left = 'auto';
                                    break;
                            }

                            if (config.buttonId == 'xFOVinput') {
                                btnElement.style.bottom = '32px';
                            }

                            // Add some styling for better visibility
                            btnElement.style.zIndex = '20';
                            btnElement.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
                            btnElement.style.color = 'white';
                            btnElement.style.border = '1px solid #ccc';
                            btnElement.style.borderRadius = '4px';
                            btnElement.style.padding = '6px 12px';
                            btnElement.style.fontSize = '12px';
                            btnElement.style.cursor = 'pointer';
                        }
                    }, 100);

                    return btn;
                } catch (error) {
                    console.error('Error creating Aladin button:', error);
                    return null;
                }
            },

            updateAladinButtonText: function (selector, newText) {
                try {
                    const btnElement = document.querySelector(selector);
                    if (btnElement) {
                        btnElement.textContent = newText;
                    }
                } catch (error) {
                    console.error('Error updating button text:', error);
                }
            },

            // Toggle marker labels visibility
            toggleMarkerLabels: function () {
                this.setShowMarkerLabels(!this.showMarkerLabels);
            },

            // Center on RA/Dec
            gotoRaDec: async function (ra, dec) {
                this.aladin.gotoRaDec(ra, dec);
                return Promise.resolve();
            },

            // Set FOV in degrees
            setFov: async function (fov) {
                this.aladin.setFov(fov);
                // Manually trigger FOV overlay updates after FOV change
                setTimeout(() => {
                    if (this.fovOverlays && this.fovOverlays.length > 0) {
                                                this.updateAllFovOverlayPositions();
                    }
                }, 100); // Small delay to ensure FOV change is processed
                return Promise.resolve();
            },

            // Set colormap with stretch options
            setColormap: async function (colormap, options) {
                try {
                    this.aladin.getBaseImageLayer().setColormap(colormap, options);
                                        return Promise.resolve();
                } catch (error) {
                    console.error('Error setting colormap:', error);
                    return Promise.reject(error);
                }
            },

            // Get current position [ra, dec]
            getPosition: function () {
                const pos = this.aladin.getRaDec();
                return pos && pos.length >= 2 ? [pos[0], pos[1]] : null;
            },

            // Get current FOV in degrees
            getFov: function () {
                const fov = this.aladin.getFov();
                return fov && fov.length > 0 ? fov[0] : 1.0; // Return width as FOV
            },


            // Add this to your Aladin initialization code
            isPointInLabel: function (x, y, bounds) {
                return x >= bounds.x &&
                    x <= bounds.x + bounds.width &&
                    y >= bounds.y &&
                    y <= bounds.y + bounds.height;
            },

            getMousePos: function (canvas, evt) {
                const rect = canvas.getBoundingClientRect();
                return {
                    x: evt.clientX - rect.left,
                    y: evt.clientY - rect.top
                };
            },

            createDSODrawFunction: function () {
                // Initialize DSO overlays array if not exists
                if (!this.dsoOverlays) {
                    this.dsoOverlays = [];
                }

                // Return a function that creates DOM overlays instead of canvas drawing
                return (source, canvasCtx, viewParams) => {
                    try {
                        // Create or update DSO overlay element
                        this.addOrUpdateDSOOverlay(source, viewParams);
                    } catch (error) {
                        console.error('Error in DSO draw function:', error);
                    }
                };
            },

            // Add or update a DSO overlay element
            addOrUpdateDSOOverlay: function(source, viewParams) {
                try {
                    const container = this.aladin.aladinDiv;
                    if (!container) return;

                    // Check if overlay already exists for this DSO
                    let existingOverlay = this.dsoOverlays.find(overlay => 
                        overlay.objId === source.data.objId
                    );

                    if (!existingOverlay) {
                        // Create new DSO overlay element
                        const dsoElement = document.createElement('div');
                        dsoElement.className = 'dso-marker';
                        dsoElement.dataset.objId = source.data.objId;
                        
                        // Get current field of view for visibility decisions
                        const fov = Math.max(viewParams.fov[0], viewParams.fov[1]);
                        
                        // Set base styles
                        dsoElement.style.cssText = `
                            position: absolute;
                            pointer-events: auto;
                            z-index: 10;
                            transform: translate(-50%, -50%);
                            cursor: pointer;
                            display: flex;
                            flex-direction: column;
                            align-items: center;
                        `;

                        // Create marker shape based on DSO type
                        const markerShape = document.createElement('div');
                        markerShape.className = 'dso-shape';
                        
                        const objPopularity = source.data.popularity || 50;
                        let opacity = 1.0;
                        if (objPopularity < 70) {
                            opacity = 0.8;
                            if (objPopularity < 40) {
                                opacity = 0.6;
                                if (objPopularity < 10) {
                                    opacity = 0.4;
                                }
                            }
                        }

                        // Calculate size based on zoom level
                        const zoom = viewParams.fov[0];
                        const pixelsPerDegree = container.offsetWidth / zoom;
                        const sizeDegrees = source.data.sizeDeg || 0.1;
                        const sizePixels = Math.max(8, sizeDegrees * pixelsPerDegree);

                        const color = source.data.color || '#7dd3fc';
                        
                        if (source.data.isEllipse) {
                            // Create elliptical marker
                            const widthDeg = source.data.widthDeg || sizeDegrees;
                            const heightDeg = source.data.heightDeg || sizeDegrees;
                            const widthPx = Math.max(8, widthDeg * pixelsPerDegree);
                            const heightPx = Math.max(8, heightDeg * pixelsPerDegree);
                            
                            markerShape.style.cssText = `
                                width: ${widthPx}px;
                                height: ${heightPx}px;
                                border: 2px solid ${color};
                                border-radius: 50%;
                                background: ${source.data.fill ? (source.data.fillColor || color + '40') : 'transparent'};
                                opacity: ${opacity};
                                transform: rotate(${source.data.rotation || 0}deg);
                            `;
                        } else {
                            // Create circular marker
                            markerShape.style.cssText = `
                                width: ${sizePixels}px;
                                height: ${sizePixels}px;
                                border: 2px solid ${color};
                                border-radius: 50%;
                                background: ${source.data.fill ? (source.data.fillColor || color + '40') : 'transparent'};
                                opacity: ${opacity};
                            `;
                        }

                        dsoElement.appendChild(markerShape);

                        // Add label if enabled and zoomed in enough
                        if (this.showMarkerLabels && source.data.showLabel !== false && fov <= 300 && source.data.label) {
                            const labelElement = document.createElement('div');
                            labelElement.className = 'dso-label';
                            labelElement.style.cssText = `
                                color: ${source.data.textColor || '#ffffff'};
                                font-size: 14px;
                                font-family: Arial, sans-serif;
                                font-weight: bold;
                                text-shadow: 1px 1px 2px rgba(0,0,0,0.8);
                                white-space: nowrap;
                                text-align: center;
                                margin-top: 4px;
                                pointer-events: none;
                                opacity: ${opacity};
                            `;
                            labelElement.textContent = source.data.label;
                            
                            // Add type label if zoomed in more
                            if (fov < 3.5 && source.data.labelType) {
                                const typeElement = document.createElement('div');
                                typeElement.style.cssText = `
                                    color: ${source.data.textColor || '#bbbbbb'};
                                    font-size: 10px;
                                    font-family: Arial, sans-serif;
                                    text-shadow: 1px 1px 2px rgba(0,0,0,0.8);
                                    white-space: nowrap;
                                    text-align: center;
                                    opacity: ${opacity * 0.8};
                                `;
                                typeElement.textContent = source.data.labelType;
                                labelElement.appendChild(typeElement);
                            }
                            
                            dsoElement.appendChild(labelElement);
                        }

                        // Add click handler
                        dsoElement.addEventListener('click', (event) => {
                            event.stopPropagation();
                            if (this.dotNetHelper && source.data.objId) {
                                this.dotNetHelper.invokeMethodAsync('SelectDSO', source.data.objId)
                                    .catch(err => console.error('Error selecting DSO:', err));
                            }
                        });

                        // Add hover effects
                        dsoElement.addEventListener('mouseenter', () => {
                            markerShape.style.transform = `${markerShape.style.transform} scale(1.2)`;
                            dsoElement.style.zIndex = '11';
                        });

                        dsoElement.addEventListener('mouseleave', () => {
                            markerShape.style.transform = markerShape.style.transform.replace(' scale(1.2)', '');
                            dsoElement.style.zIndex = '10';
                        });

                        container.appendChild(dsoElement);

                        // Store overlay data
                        existingOverlay = {
                            element: dsoElement,
                            objId: source.data.objId,
                            ra: source.ra,
                            dec: source.dec,
                            source: source
                        };
                        
                        this.dsoOverlays.push(existingOverlay);
                    }

                    // Update position for both new and existing overlays
                    this.updateDSOOverlayPosition(existingOverlay);

                } catch (error) {
                    console.error('Error adding/updating DSO overlay:', error);
                }
            },

            // Update DSO overlay position
            updateDSOOverlayPosition: function(overlay) {
                try {
                    if (!overlay || !overlay.element) return;

                    // Use Aladin's coordinate transformation like astronomical overlays
                    const pixelCoords = this.aladin.world2pix(overlay.ra * 15, overlay.dec);
                    
                    if (!pixelCoords || pixelCoords.length < 2) {
                        // DSO is outside current view
                        overlay.element.style.display = 'none';
                        return;
                    }

                    const [x, y] = pixelCoords;
                    
                    // Check if DSO is within visible bounds (with margin)
                    const containerWidth = this.aladin.aladinDiv.offsetWidth;
                    const containerHeight = this.aladin.aladinDiv.offsetHeight;
                    
                    if (x < -50 || x > containerWidth + 50 || 
                        y < -50 || y > containerHeight + 50) {
                        overlay.element.style.display = 'none';
                        return;
                    }

                    // Position the DSO marker
                    overlay.element.style.display = 'flex';
                    overlay.element.style.left = `${x}px`;
                    overlay.element.style.top = `${y}px`;

                } catch (error) {
                    console.error('Error updating DSO overlay position:', error);
                    if (overlay.element) {
                        overlay.element.style.display = 'none';
                    }
                }
            },

            // Update all DSO overlay positions
            updateAllDSOPositions: function() {
                try {
                    if (!this.dsoOverlays) return;
                    
                    this.dsoOverlays.forEach(overlay => {
                        this.updateDSOOverlayPosition(overlay);
                    });
                } catch (error) {
                    console.error('Error updating all DSO positions:', error);
                }
            },

            // Clear all DSO overlays
            clearDSOOverlays: function() {
                try {
                    if (!this.dsoOverlays) return;
                    
                    this.dsoOverlays.forEach(overlay => {
                        if (overlay.element && overlay.element.parentNode) {
                            overlay.element.parentNode.removeChild(overlay.element);
                        }
                    });
                    
                    this.dsoOverlays = [];
                } catch (error) {
                    console.error('Error clearing DSO overlays:', error);
                }
            },

            // Set up event listeners for automatic position updates
            setupDSOEventListeners: function() {
                try {
                    if (!this.aladin) return;

                    // Update DSO positions when view changes
                    const updatePositions = () => {
                        this.updateAllDSOPositions();
                    };

                    // Listen for view changes
                    this.aladin.on('zoomChanged', updatePositions);
                    this.aladin.on('positionChanged', updatePositions);
                    
                                    } catch (error) {
                    console.error('Error setting up DSO event listeners:', error);
                }
            },

            // Add a marker at RA/Dec with options
            addMarker: async function (ra, dec, pa, options = {}) {
                if (typeof options === 'string') {
                    options = { label: options };
                }

                try {
                    var isEllipse = false;
                    const MIN_SIZE_DEGREES = 0.1; // Minimum size in degrees (~6 arcmin)
                    const LIGHT_BLUE = '#7dd3fc'; // Light blue color

                    // Calculate marker size in degrees (convert from arcminutes)
                    // Use sizeArcmin if available, otherwise use a default size
                    const sizeArcminMin = options.sizeArcminMin || 10; // Default to 10 arcmin if no size provided
                    const sizeArcminMax = options.sizeArcminMax || 10; // Default to 10 arcmin if no size provided

                    const majorAxis = Math.max(MIN_SIZE_DEGREES, (sizeArcminMax / 60) * 1.2) * 0.6;
                    const minorAxis = Math.max(MIN_SIZE_DEGREES, (sizeArcminMin / 60) * 1.2) * 0.6;

                    // check if both sizes are available and one of them is bigger than the other by a certain factor so that an ellipse is better
                    if (sizeArcminMax && sizeArcminMin && sizeArcminMax > sizeArcminMin * 1.2) {
                        isEllipse = true;
                    }

                    // Store marker info for label handling
                    const markerInfo = {
                        ra,
                        dec,
                        label: options.label || '',
                        labelType: options.type,
                        popularity: options.popularity,
                        objId: options.objId,
                        color: options.color,
                        element: null,
                        visible: this.showMarkerLabels,
                        sizeDeg: majorAxis,
                        widthDeg: majorAxis,
                        heightDeg: minorAxis,
                        markerSize: isEllipse
                            ? { width: majorAxis, height: minorAxis, isEllipse: true }
                            : { width: majorAxis, height: majorAxis, isEllipse: false },
                        isEllipse: isEllipse,
                        rotation: pa
                    };


                    // Create a catalog for the marker if it doesn't exist
                    if (!this.dsoCatalog) {
                        this.dsoCatalog = A.catalog({
                            name: 'DSO_Markers',
                            shape: this.createDSODrawFunction()
                            // onClick: 'showPopup'
                        });

                        this.dsoCatalog.setSelectionColor('#fce303');
                        this.aladin.addCatalog(this.dsoCatalog);
                    }


                    // Create source with custom data
                    const source = A.source(markerInfo.ra, markerInfo.dec, {
                        label: markerInfo.label,
                        labelType: markerInfo.labelType,
                        popularity: markerInfo.popularity,
                        objId: markerInfo.objId,
                        color: markerInfo.color || '#ff0000',
                        sizeDeg: markerInfo.sizeDeg || 10,
                        isEllipse: markerInfo.isEllipse || false,
                        rotation: markerInfo.rotation,
                        widthDeg: markerInfo.widthDeg || markerInfo.size || 10,
                        heightDeg: markerInfo.heightDeg || markerInfo.size || 10,
                        showLabel: this.showMarkerLabels,
                        // Add any other custom properties you need
                        popupTitle: markerInfo.label,
                        popupDesc: this.getDSOPopupContent(markerInfo),
                        popupClass: 'dso-popup',
                        popupPos: 'bottom'
                    });

                    // Add the source to the catalog
                    this.dsoCatalog.addSources([source]);

                    // Store source info
                    markerInfo.source = source;
                    this.markers.push(markerInfo);


                    return source;

                } catch (error) {
                    console.error('Error adding marker:', error);
                    throw error;
                }
            },

            addDSOMarkers: function (markers) {
                if (!this.aladin || !markers || !markers.length) return;

                markers.forEach(marker => {
                    // Create a catalog for the marker if it doesn't exist
                    if (!this.dsoCatalog) {
                        this.dsoCatalog = A.catalog({
                            name: 'DSO_Markers',
                            shape: this.createDSODrawFunction()
                            // onClick: 'showPopup'
                        });

                        this.dsoCatalog.setSelectionColor('#fce303');
                        this.aladin.addCatalog(this.dsoCatalog);
                    }

                    // Add the source to the catalog
                    this.dsoCatalog.addSources([marker.source]);
                });

                //this.aladin.repaint();
            },

            // In the returned object, add this method:
            redrawMarkers: function () {
                if (!this.aladin) return;

                // Clear all markers
                this.clearMarkers(false);

                // Re-add all sources
                if (this.markers && this.markers.length > 0) {
                    this.addDSOMarkers(this.markers);
                }
            },

            // Add method to generate popup content
            getDSOPopupContent: function (markerInfo) {
                const content = document.createElement('div');
                content.className = 'dso-popup-content';
                content.innerHTML = `
                    <div class="dso-popup-header">
                        <h3>${markerInfo.label}</h3>
                        ${markerInfo.type ? `<span class="dso-type">${markerInfo.type}</span>` : ''}
                    </div>
                    <div class="dso-popup-body">
                        ${markerInfo.magnitude ? `<div><strong>Magnitude:</strong> ${markerInfo.magnitude}</div>` : ''}
                        ${markerInfo.size ? `<div><strong>Size:</strong> ${markerInfo.size}'</div>` : ''}
                        ${markerInfo.constellation ? `<div><strong>Constellation:</strong> ${markerInfo.constellation}</div>` : ''}
                    </div>
                    <div class="dso-popup-actions">
                        <button class="dso-btn dso-btn-select" 
                                data-identifier="${markerInfo.label}">
                            Select
                        </button>
                        <button class="dso-btn dso-btn-details" 
                                data-identifier="${markerInfo.label}">
                            View Details
                        </button>
                    </div>
                `;

                // Add event listeners to the buttons
                const selectBtn = content.querySelector('.dso-btn-select');
                const detailsBtn = content.querySelector('.dso-btn-details');

                if (selectBtn) {
                    selectBtn.addEventListener('click', (e) => {
                        e.stopPropagation();
                        if (window.dotNetHelper) {
                            window.dotNetHelper.invokeMethodAsync('SelectDSO', markerInfo.label);
                        }
                        // Close the popup
                        const popup = content.closest('.aladin-popup');
                        if (popup) {
                            popup.style.display = 'none';
                        }
                    });
                }

                if (detailsBtn) {
                    detailsBtn.addEventListener('click', (e) => {
                        e.stopPropagation();
                        if (window.dotNetHelper) {
                            window.dotNetHelper.invokeMethodAsync('ViewDSODetails', markerInfo.label);
                        }
                        // Close the popup
                        const popup = content.closest('.aladin-popup');
                        if (popup) {
                            popup.style.display = 'none';
                        }
                    });
                }

                return content.innerHTML;
            },

            // Create a label element for a marker
            createMarkerLabel: function (markerInfo) {
                if (markerInfo.element) return; // Already has a label

                const container = document.getElementById(this.aladin.aladinDiv.id);
                if (!container) {
                    console.warn('Aladin container not found, cannot create marker label');
                    return;
                }

                // Create the label element
                const label = document.createElement('div');
                label.className = 'marker-label';
                label.textContent = markerInfo.label;

                // Style the label with a semi-transparent background
                label.style.cssText = `
                    position: absolute;
                    background-color: rgba(0, 0, 0, 0.7);
                    color: white;
                    padding: 2px 8px;
                    border-radius: 4px;
                    font-family: Arial, sans-serif;
                    font-size: 12px;
                    white-space: nowrap;
                    pointer-events: none;
                    z-index: 1000;
                    text-align: center;
                    transform-origin: center;
                    will-change: transform;
                    text-shadow: 0 0 2px black, 0 0 2px black, 0 0 2px black; /* Better text visibility */
                `;

                container.appendChild(label);
                markerInfo.element = label;

                // Initial position update
                this.updateMarkerLabelPosition(markerInfo);
            },

            // Update label position based on current view
            updateMarkerLabelPosition: function (markerInfo) {
                if (!markerInfo.element || !markerInfo.visible) {
                    if (markerInfo.element) markerInfo.element.style.display = 'none';
                    return;
                }

                const pos = this.aladin.world2pix(markerInfo.ra, markerInfo.dec);
                if (pos) {
                    const aladinDiv = document.getElementById(this.aladin.aladinDiv.id);
                    if (!aladinDiv) return;

                    const x = pos[0];
                    const y = pos[1];

                    // Position the label based on the current mode
                    if (this.labelPosition === 'below') {
                        // Calculate offset based on marker size in pixels
                        const markerSizePx = markerInfo.markerSize.isEllipse
                            ? Math.max(markerInfo.markerSize.width, markerInfo.markerSize.height) * 60 // Convert to arcmin
                            : markerInfo.size * 60; // Convert to arcmin

                        // Convert arcmin to pixels at current zoom level
                        const fov = this.aladin.getFov()[0]; // FOV in degrees
                        const containerHeight = aladinDiv.clientHeight;
                        const degreesPerPixel = fov / containerHeight;
                        const arcminPerPixel = degreesPerPixel * 60;
                        const offsetPx = (markerSizePx / arcminPerPixel) / 2 + 15; // Half the marker size + padding

                        markerInfo.element.style.left = `${x}px`;
                        markerInfo.element.style.top = `${y + offsetPx}px`;
                        markerInfo.element.style.transform = 'translate(-50%, 0)';
                    } else {
                        // Center position (default)
                        markerInfo.element.style.left = `${x}px`;
                        markerInfo.element.style.top = `${y}px`;
                        markerInfo.element.style.transform = 'translate(-50%, -50%)';
                    }

                    markerInfo.element.style.textAlign = 'center';
                    markerInfo.element.style.display = 'block';

                    // Check if the label is within the visible area
                    const aladinRect = aladinDiv.getBoundingClientRect();

                    // Hide if the marker is outside the viewport
                    if (x < 0 || x > aladinRect.width || y < 0 || y > aladinRect.height) {
                        markerInfo.element.style.display = 'none';
                    }
                } else {
                    // Hide label if position is not valid
                    markerInfo.element.style.display = 'none';
                }
            },

            // Update all marker label positions
            updateAllMarkerLabels: function () {
                this.markers.forEach(marker => {
                    if (marker.element) {
                        this.updateMarkerLabelPosition(marker);
                    }
                });
            },

            // Toggle all marker labels
            setShowMarkerLabels: function (show) {
                this.showMarkerLabels = !!show;
                this.markers.forEach(marker => {
                    if (this.showMarkerLabels) {
                        if (!marker.element) {
                            this.createMarkerLabel(marker);
                        } else {
                            marker.element.style.display = 'block';
                        }
                        this.updateMarkerLabelPosition(marker);
                    } else if (marker.element) {
                        marker.element.style.display = 'none';
                    }
                });
            },

            // Set label position ('center' or 'below')
            setLabelPosition: function (position) {
                if (position === 'center' || position === 'below') {
                    this.labelPosition = position;
                    this.updateAllMarkerLabels();
                    return true;
                }
                return false;
            },

            // Toggle between center and below positions
            toggleLabelPosition: function () {
                this.setLabelPosition(this.labelPosition === 'center' ? 'below' : 'center');
            },

            // Clear all markers and their labels
            clearMarkers: function (deleteMarkers = true) {
                try {
                                        
                    // Clear DSO overlays first
                    this.clearDSOOverlays();
                    
                    // Store label positions for hit testing
                    this.labelPositions = [];

                    // Remove the marker overlay if it exists
                    if (this.markerOverlay) {
                        this.markerOverlay.remove();
                        this.markerOverlay = null;
                    }

                    // Remove all label elements
                    if (this.markers) {
                        this.markers.forEach(markerInfo => {
                            if (markerInfo.element && markerInfo.element.parentNode) {
                                markerInfo.element.parentNode.removeChild(markerInfo.element);
                            }
                        });
                    }

                    if (this.dsoCatalog) {
                        this.dsoCatalog.removeAll();

                        try {
                            this.aladin.removeCatalog(this.dsoCatalog.name);
                        } catch (err) { 
                            console.warn('Error removing DSO catalog:', err);
                        }
                        
                        this.dsoCatalog = null;
                                            }
                    
                    if (deleteMarkers == true) {
                        this.markers = [];
                                            }
                    
                                    } catch (e) {
                    console.error('Error clearing markers:', e);
                }
            },

            // Set the survey (background image)
            setSurvey: async function (surveyId) {
                try {
                    /*
                    // Remove all existing base image layers
                    const currentBaseLayer = this.aladin.getBaseImageLayer();
                    if (currentBaseLayer) {
                        this.aladin.removeImageSurvey(currentBaseLayer);
                    }
                    */

                    // Create and set the new survey
                    const survey = await this.aladin.newImageSurvey(surveyId);
                    this.aladin.setBaseImageLayer(survey);
                    return Promise.resolve();
                } catch (e) {
                    console.error('Error setting survey:', e);
                    return Promise.reject(e);
                }
            },

            // Get current view parameters (RA, Dec, FOV)
            getViewParams: function () {
                const center = aladin.getRaDec();
                const fov = aladin.getFov(); // This returns [width, height]

                return {
                    ra: center[0],
                    dec: center[1],
                    fov: fov[0]
                };
            },

            // Zoom in
            zoomIn: async function () {
                try {
                    const currentZoom = this.aladin.getFov()[0];
                    this.aladin.setZoomFactor(currentZoom * 0.7); // Zoom in by reducing FOV
                    return Promise.resolve();
                } catch (e) {
                    console.error('Error zooming in:', e);
                    return Promise.reject(e);
                }
            },

            // Zoom out
            zoomOut: async function () {
                try {
                    const currentZoom = this.aladin.getFov()[0];
                    this.aladin.setZoomFactor(currentZoom * 1.3); // Zoom out by increasing FOV
                    return Promise.resolve();
                } catch (e) {
                    console.error('Error zooming out:', e);
                    return Promise.reject(e);
                }
            },

            // Destroy the Aladin instance
            destroy: async function () {
                try {
                    // Clear markers first
                    await this.clearMarkers();

                    // Destroy the Aladin instance
                    if (this.aladin) {
                        this.aladin.destroy();
                    }

                    return Promise.resolve();
                } catch (e) {
                    console.error('Error destroying Aladin instance:', e);
                    return Promise.reject(e);
                }
            },

            // Show/hide grid
            showGrid: async function (isVisible) {
                try {
                    this.aladin.setCooGrid({ enabled: isVisible });

                    return Promise.resolve();
                } catch (e) {
                    console.error('Error showing/hiding grid:', e);
                    return Promise.reject(e);
                }
            },

            // Show/hide reticle
            showAladinReticle: async function (isVisible) {
                try {
                    this.aladin.showReticle(isVisible);

                    return Promise.resolve();
                } catch (e) {
                    console.error('Error showing/hiding reticle:', e);
                    return Promise.reject(e);
                }
            },

            // Multiple FOV Overlay Management
            updateFovOverlays: async function (overlays) {
                try {
                    // Clear existing overlays
                    this.clearAllFovOverlays();

                    // Add new overlays
                    if (overlays && overlays.length > 0) {
                        overlays.forEach(overlay => {
                            if (overlay.isVisible) {
                                this.addFovOverlay(overlay);
                            }
                        })
                    }

                    return Promise.resolve();
                } catch (e) {
                    console.error('Error updating FOV overlays:', e);
                    return Promise.reject(e);
                }
            },

            addFovOverlay: function (overlay) {
                try {
                    const container = this.aladin.aladinDiv;
                    if (!container) return;

                    // Create overlay element
                    const overlayElement = document.createElement('div');
                    overlayElement.id = `fov-overlay-${overlay.id}`;
                    overlayElement.className = 'fov-overlay';
                    overlayElement.style.cssText = `
                        position: absolute;
                        border: 2px dashed ${overlay.color};
                        background: transparent;
                        pointer-events: none;
                        z-index: 10;
                        transform-origin: center center;
                    `;

                    container.appendChild(overlayElement);

                    // Store overlay data
                    this.fovOverlays.push({
                        id: overlay.id,
                        data: overlay,
                        element: overlayElement
                    });

                    this.fovOverlayElements.set(overlay.id, overlayElement);

                    // Update overlay position and size
                    this.updateFovOverlayPosition(overlay.id);

                } catch (e) {
                    console.error('Error adding FOV overlay:', e);
                }
            },

            removeFovOverlay: function (overlayId) {
                try {
                    const element = this.fovOverlayElements.get(overlayId);
                    if (element && element.parentNode) {
                        element.parentNode.removeChild(element);
                    }

                    this.fovOverlayElements.delete(overlayId);
                    this.fovOverlays = this.fovOverlays.filter(o => o.id !== overlayId);

                } catch (e) {
                    console.error('Error removing FOV overlay:', e);
                }
            },

            clearAllFovOverlays: function () {
                try {
                    this.fovOverlayElements.forEach((element, id) => {
                        if (element && element.parentNode) {
                            element.parentNode.remove();
                        }
                    });

                    this.fovOverlayElements.clear();
                    this.fovOverlays = [];

                } catch (e) {
                    console.error('Error clearing FOV overlays:', e);
                }
            },


            // Remove image layer
            removeImageLayer: function (layer) {
                this.aladin.removeImageLayer(layer);
            },

            updateAllFovOverlayPositions: function () {
                this.updateFovOverlayPosition();
            },


            updateFovOverlayPosition: function (overlayId = null) {
                try {
                    const overlaysToUpdate = overlayId
                        ? this.fovOverlays.filter(o => o.id === overlayId)
                        : this.fovOverlays;

                    overlaysToUpdate.forEach(overlay => {
                        const element = overlay.element;
                        const data = overlay.data;

                        if (!element || !data) return;

                        // Get current view center
                        const center = this.aladin.getRaDec();
                        if (!center || center.length < 2) return;

                        // Calculate overlay dimensions in pixels
                        const fov = this.aladin.getFov();
                        const containerWidth = this.aladin.aladinDiv.offsetWidth;
                        const containerHeight = this.aladin.aladinDiv.offsetHeight;

                        const pixelsPerDegree = containerWidth / fov[0];

                        // Convert FOV from arcminutes to degrees, then to pixels
                        const overlayWidthPx = (data.widthArcmin / 60) * pixelsPerDegree;
                        const overlayHeightPx = (data.heightArcmin / 60) * pixelsPerDegree;

                        // Position overlay at center of view
                        const centerX = containerWidth / 2;
                        const centerY = containerHeight / 2;

                        // Create or update the unified container for FOV + label
                        let container = overlay.container;
                        if (!container) {
                            // Create container div that holds both FOV overlay and label
                            container = document.createElement('div');
                            container.className = 'fov-container';
                            container.style.position = 'absolute';
                            container.style.pointerEvents = 'none';
                            container.style.transformOrigin = 'center center';

                            // Move the existing FOV element into the container
                            const parent = element.parentNode;
                            parent.insertBefore(container, element);
                            container.appendChild(element);

                            // Create label element within the container
                            const labelElement = document.createElement('div');
                            labelElement.className = 'fov-label';
                            labelElement.style.position = 'absolute';
                            labelElement.style.color = 'white';
                            labelElement.style.fontSize = '12px';
                            labelElement.style.fontWeight = 'bold';
                            labelElement.style.textShadow = '1px 1px 2px rgba(0,0,0,0.8)';
                            labelElement.style.whiteSpace = 'nowrap';
                            labelElement.style.pointerEvents = 'none';
                            labelElement.textContent = data.labelText || '';

                            container.appendChild(labelElement);

                            // Store references
                            overlay.container = container;
                            overlay.labelElement = labelElement;
                        }

                        // Position the container at the center
                        container.style.left = `${centerX}px`;
                        container.style.top = `${centerY}px`;
                        container.style.transform = `rotate(${data.rotationDegrees}deg)`;
                        container.style.display = data.isVisible ? 'block' : 'none';

                        // Position FOV overlay within container (centered)
                        element.style.width = `${overlayWidthPx}px`;
                        element.style.height = `${overlayHeightPx}px`;
                        element.style.left = `${-overlayWidthPx / 2}px`;
                        element.style.top = `${-overlayHeightPx / 2}px`;
                        element.style.transform = 'none'; // No rotation needed, container handles it
                        element.style.borderColor = data.color;

                        // Position label within container (switch sides based on rotation to keep text readable)
                        const labelElement = overlay.labelElement;
                        if (labelElement) {
                            labelElement.textContent = data.labelText || '';
                            labelElement.style.left = '50%';
                            labelElement.style.color = data.color; // Use same color as FOV overlay

                            // Position label based on rotation to keep text readable
                            const rotation = (data.rotationDegrees || 0) % 360;
                            const normalizedRotation = rotation < 0 ? rotation + 360 : rotation;

                            // If rotation would make text upside down (90° to 270°), flip to opposite side
                            if (normalizedRotation > 90 && normalizedRotation < 270) {
                                labelElement.style.top = `${-overlayHeightPx / 2 - 25}px`; // 25px above FOV top edge
                                // Add 180° rotation to flip text right-side up when on opposite side
                                labelElement.style.transform = `translateX(-50%) rotate(180deg)`;
                            } else {
                                labelElement.style.top = `${overlayHeightPx / 2 + 10}px`; // 10px below FOV bottom edge
                                // No additional rotation needed
                                labelElement.style.transform = `translateX(-50%)`;
                            }
                        }
                    });

                } catch (e) {
                    console.error('Error updating FOV overlay positions:', e);
                }
            },
            // Show/hide all markers
            setMarkersVisible: function (visible) {
                try {
                    if (this.dsoCatalog) {
                        if (visible) {
                            this.dsoCatalog.show();
                        } else {
                            this.dsoCatalog.hide();
                        }

                        // Toggle marker labels visibility
                        // this.setShowMarkerLabels(visible);

                        // Trigger a redraw
                        //this.aladin.repaint();
                    }
                    return Promise.resolve();
                } catch (e) {
                    console.error('Error toggling markers visibility:', e);
                    return Promise.reject(e);
                }
            }
        };

        // Initial update
        updateCoordinates();

        // Add event listeners to update coordinates
        if (aladin.view && aladin.view.targetChanged) {
            aladin.view.targetChanged.add(() => {
                try {
                    const center = aladin.getRaDec();
                    const fov = aladin.getFov(); // This returns [width, height]
                    const fovWidth = fov[0];     // Get the width (first element)

                    if (center && dotNetHelper) {
                        dotNetHelper.invokeMethodAsync('UpdateCoordinates', {
                            ra: center[0],
                            dec: center[1],
                            fov: fovWidth
                        }).catch(e => console.error('Error in UpdateCoordinates:', e));
                    }
                } catch (e) {
                    console.error('Error in targetChanged handler:', e);
                }
            });
        }

        // Add resize observer to update overlays when container resizes
        if (window.ResizeObserver) {
            const resizeObserver = new ResizeObserver(() => {
                // Update FOV overlays
                aladinInstance.updateAllFovOverlayPositions();
                // Update mosaic panels if they exist
                if (aladinInstance.updateMosaicPanelPositions) {
                    aladinInstance.updateMosaicPanelPositions();
                }
            });
            resizeObserver.observe(aladinInstance.aladin.aladinDiv);
        }

        // Extend Aladin instance with mosaic functionality
        if (typeof window.extendAladinWithMosaic === 'function') {
                        window.extendAladinWithMosaic(aladinInstance);
        } else {
            console.warn('extendAladinWithMosaic function not available - mosaic functionality will not work');
        }

        // Extend Aladin instance with astronomical functionality
        if (typeof window.extendAladinWithAstronomical === 'function') {
                        window.extendAladinWithAstronomical(aladinInstance);
        } else {
            console.warn('extendAladinWithAstronomical function not available - astronomical functionality will not work');
        }

        // Set up DSO event listeners for automatic position updates
        aladinInstance.setupDSOEventListeners();

        // Add global functions for Blazor to call
        window.getAladinPosition = () => aladinInstance.getPosition();
        window.getAladinFov = () => aladinInstance.getFov();
        window.addAladinMarker = (ra, dec, pa, label, color, sizeArcminMin, sizeArcminMax, type, popularity, objId) =>
            aladinInstance.addMarker(ra, dec, pa, {
                label,
                color,
                sizeArcminMin,
                sizeArcminMax,
                type,
                popularity,
                objId
            });
        window.clearAladinMarkers = () => aladinInstance.clearMarkers();
        window.setMarkerLabelsVisible = (visible) => aladinInstance.setShowMarkerLabels(visible);
        window.toggleMarkerLabels = () => aladinInstance.toggleMarkerLabels();

        // Store global reference for mosaic functions
        window.aladinInstance = aladinInstance;

        // Return the Aladin instance
        return aladinInstance;
    } catch (error) {
        console.error('Error initializing Aladin Lite:', error);
        throw error;
    }
}

// Update coordinate display in the UI
export function updateCoordinateDisplay(ra, dec, fov) {
    const raDisplay = document.getElementById('ra-display');
    const decDisplay = document.getElementById('dec-display');
    const fovDisplay = document.getElementById('fov-display');

    if (raDisplay) {
        // Format RA as HH:MM:SS
        const raHours = Math.floor(ra / 15);
        const raMinutes = Math.floor((ra / 15 - raHours) * 60);
        const raSeconds = ((ra / 15 - raHours - raMinutes / 60) * 3600).toFixed(1);
        raDisplay.textContent = `${raHours}h ${raMinutes}m ${raSeconds}s`;
    }

    if (decDisplay) {
        // Format Dec as DD°MM'SS"
        const decSign = dec >= 0 ? '+' : '-';
        const decAbs = Math.abs(dec);
        const decDeg = Math.floor(decAbs);
        const decMinutes = Math.floor((decAbs - decDeg) * 60);
        const decSeconds = ((decAbs - decDeg - decMinutes / 60) * 3600).toFixed(0);
        decDisplay.textContent = `${decSign}${decDeg}° ${decMinutes}' ${decSeconds}"`;
    }

    if (fovDisplay) {
        // Format FOV
        if (fov >= 1) {
            fovDisplay.textContent = `${fov.toFixed(1)}°`;
        } else if (fov >= 1 / 60) {
            fovDisplay.textContent = `${(fov * 60).toFixed(1)}'`;
        } else {
            fovDisplay.textContent = `${(fov * 3600).toFixed(1)}"`;
        }
    }
}