// Mini Aladin viewer for showing mount position
// Lightweight version without full SkyAtlas features

let aladinInstances = new Map();

function looksLikeBootstrappedAladinApi(value) {
    return !!value
        && typeof value.aladin === 'function'
        && typeof value.init?.then === 'function';
}

function getAladinApi() {
    if (looksLikeBootstrappedAladinApi(window.__amAladinApi)) {
        return window.__amAladinApi;
    }

    return window.A;
}

export async function initializeMiniAladin(divId, options, dotnetRef) {
    // Wait for A global to be available
    await waitForAladin();
    
    const container = document.getElementById(divId);
    if (!container) {
        console.error('MiniAladin: Container not found:', divId);
        return null;
    }
    
    // Convert RA from hours (0-24) to degrees (0-360) for Aladin
    const raDegrees = options.ra * 15;
    
    const aladinApi = getAladinApi();
    const aladin = aladinApi.aladin(`#${divId}`, {
        target: `${raDegrees} ${options.dec}`,
        fov: options.fov,
        survey: options.survey || 'P/DSS2/color',
        showReticle: true,
        showZoomControl: true,
        showFullscreenControl: false,
        showLayersControl: false,
        showGotoControl: false,
        showShareControl: false,
        showCooGridControl: false,
        showSimbadPointerControl: false,
        showFrame: false,
        cooFrame: 'J2000'
    });
    
    // Add marker for mount position
    const catalog = aladinApi.catalog({ name: 'Mount Position', sourceSize: 18, color: '#00FF00' });
    aladin.addCatalog(catalog);
    
    // Store mount position (in hours for display)
    let mountRaHours = options.ra;
    let mountDec = options.dec;
    
    if (options.ra !== 0 || options.dec !== 0) {
        catalog.addSources([aladinApi.marker(raDegrees, options.dec, {
            popupTitle: 'Mount Position',
            popupDesc: `RA: ${formatRA(options.ra)}<br>Dec: ${formatDec(options.dec)}`
        })]);
    }
    
    const fovOverlayDefinitions = resolveFovOverlayDefinitions(options);
    const fovOverlays = createFovOverlays(aladin, fovOverlayDefinitions);
    updateFovOverlays(fovOverlays, fovOverlayDefinitions, raDegrees, options.dec, options.showFovOverlay);
    
    // Store instance with dotnet reference for callbacks
    aladinInstances.set(divId, {
        aladin,
        catalog,
        dotnetRef,
        mountRaHours,
        mountDec,
        fovOverlays,
        fovOverlayDefinitions,
        fovOptions: options,
        equipmentName: options.equipmentName
    });
    
    return { divId };
}

export function updatePosition(instance, raHours, dec) {
    if (!instance || !instance.divId) return;
    
    const data = aladinInstances.get(instance.divId);
    if (!data) return;
    
    const { aladin, catalog, fovOverlays, fovOverlayDefinitions, fovOptions } = data;
    
    // Convert RA from hours to degrees for Aladin
    const raDegrees = raHours * 15;
    
    // Update stored mount position
    data.mountRaHours = raHours;
    data.mountDec = dec;
    
    // Center on new position
    aladin.gotoRaDec(raDegrees, dec);
    
    // Update marker
    catalog.removeAll();
    const aladinApi = getAladinApi();
    catalog.addSources([aladinApi.marker(raDegrees, dec, {
        popupTitle: 'Mount Position',
        popupDesc: `RA: ${formatRA(raHours)}<br>Dec: ${formatDec(dec)}`
    })]);
    
    // Update FOV overlay position if enabled
    updateFovOverlays(fovOverlays, fovOverlayDefinitions, raDegrees, dec, fovOptions?.showFovOverlay);
}

export function dispose(instance) {
    if (instance && instance.divId) {
        aladinInstances.delete(instance.divId);
    }
}

export function getCurrentViewCenter(instance) {
    if (!instance || !instance.divId) return null;
    
    const data = aladinInstances.get(instance.divId);
    if (!data) return null;
    
    const { aladin } = data;
    const [raDeg, dec] = aladin.getRaDec();
    
    // Convert RA from degrees back to hours for consistency
    const raHours = raDeg / 15;
    
    return { raHours, dec };
}

export function goToMountPosition(instance) {
    if (!instance || !instance.divId) return;
    
    const data = aladinInstances.get(instance.divId);
    if (!data) return;
    
    const { aladin, mountRaHours, mountDec } = data;
    const raDegrees = mountRaHours * 15;
    aladin.gotoRaDec(raDegrees, mountDec);
}

function formatRA(ra) {
    // Convert decimal hours to HMS
    const hours = Math.floor(ra);
    const minutes = Math.floor((ra - hours) * 60);
    const seconds = ((ra - hours) * 60 - minutes) * 60;
    return `${hours}h ${minutes}m ${seconds.toFixed(1)}s`;
}

function formatDec(dec) {
    // Convert decimal degrees to DMS
    const sign = dec >= 0 ? '+' : '-';
    const absDec = Math.abs(dec);
    const degrees = Math.floor(absDec);
    const minutes = Math.floor((absDec - degrees) * 60);
    const seconds = ((absDec - degrees) * 60 - minutes) * 60;
    return `${sign}${degrees}° ${minutes}' ${seconds.toFixed(1)}"`;
}

// Update FOV overlay rectangle at given position
function updateFovOverlay(overlay, raDeg, dec, widthDeg, heightDeg, rotationDeg, color, equipmentName) {
    if (!overlay) return;
    
    overlay.removeAll();
    
    // Calculate the four corners of the FOV rectangle
    // Apply rotation around center point
    const halfWidth = widthDeg / 2;
    const halfHeight = heightDeg / 2;
    const rotRad = rotationDeg * Math.PI / 180;
    const cosRot = Math.cos(rotRad);
    const sinRot = Math.sin(rotRad);
    
    // Corners before rotation (relative to center)
    const corners = [
        [-halfWidth, -halfHeight],
        [halfWidth, -halfHeight],
        [halfWidth, halfHeight],
        [-halfWidth, halfHeight]
    ];
    
    // Apply rotation and translate to absolute coordinates
    // Note: RA increases to the left (west), so we negate the RA offset
    const cosDec = Math.cos(dec * Math.PI / 180);
    const rotatedCorners = corners.map(([dx, dy]) => {
        const rotX = dx * cosRot - dy * sinRot;
        const rotY = dx * sinRot + dy * cosRot;
        // Correct for spherical projection at this declination
        const raOffset = rotX / cosDec;
        return [raDeg - raOffset, dec + rotY];
    });
    
    // Close the polygon by adding first point at end
    rotatedCorners.push(rotatedCorners[0]);
    
    // Create polyline for the FOV rectangle with dashed style like standard SkyAtlas
    const aladinApi = getAladinApi();
    const polyline = aladinApi.polyline(rotatedCorners, {
        color: color,
        lineWidth: 2,
        lineDash: [5, 5]  // Dashed line like standard equipment FOV overlay
    });
    overlay.add(polyline);
    
    // Add label at top of FOV rectangle
    const labelRa = rotatedCorners[0][0];
    const labelDec = rotatedCorners[0][1] + 0.05; // Slightly above the top-left corner
    const fovLabel = equipmentName || 'Equipment FOV';
    const marker = aladinApi.marker(labelRa, labelDec, {
        popupTitle: fovLabel,
        popupDesc: `${(widthDeg * 60).toFixed(1)}' x ${(heightDeg * 60).toFixed(1)}'`
    });
    overlay.add(marker);
}

// Set grid visibility
export function setGrid(instance, visible) {
    if (!instance || !instance.divId) return;
    
    const data = aladinInstances.get(instance.divId);
    if (!data) return;
    
    const { aladin } = data;
    if (aladin.setGridConfig) {
        aladin.setGridConfig({ enabled: visible });
    }
}

// Set reticle visibility
export function setReticle(instance, visible) {
    if (!instance || !instance.divId) return;
    
    const data = aladinInstances.get(instance.divId);
    if (!data) return;
    
    const { aladin } = data;
    if (aladin.showReticle !== undefined) {
        aladin.showReticle = visible;
    }
}

// Set survey
export function setSurvey(instance, surveyId) {
    if (!instance || !instance.divId) return;
    
    const data = aladinInstances.get(instance.divId);
    if (!data) return;
    
    const { aladin } = data;
    aladin.setImageSurvey(surveyId);
}

// Toggle FOV overlay visibility
export function setFovVisibility(instance, visible) {
    if (!instance || !instance.divId) return;
    
    const data = aladinInstances.get(instance.divId);
    if (!data || !data.fovOverlays) return;
    
    if (data.fovOptions) {
        data.fovOptions.showFovOverlay = visible;
    }
    
    const raDegrees = data.mountRaHours * 15;
    updateFovOverlays(data.fovOverlays, data.fovOverlayDefinitions, raDegrees, data.mountDec, visible);
}

export function updateFovConfig(instance, options) {
    if (!instance || !instance.divId) return;

    const data = aladinInstances.get(instance.divId);
    if (!data) return;

    data.fovOptions = options;
    data.fovOverlayDefinitions = resolveFovOverlayDefinitions(options);
    clearFovOverlays(data.fovOverlays);
    data.fovOverlays = createFovOverlays(data.aladin, data.fovOverlayDefinitions);
    const raDegrees = (options.ra ?? data.mountRaHours) * 15;
    const dec = options.dec ?? data.mountDec;
    updateFovOverlays(data.fovOverlays, data.fovOverlayDefinitions, raDegrees, dec, options.showFovOverlay);
}

async function waitForAladin() {
    if (window.astroAppAssets?.ensureAladinReady) {
        await window.astroAppAssets.ensureAladinReady();
    }

    const maxWait = 10000;
    const interval = 100;
    const startTime = Date.now();

    while (typeof getAladinApi() === 'undefined' && Date.now() - startTime < maxWait) {
        await new Promise(resolve => setTimeout(resolve, interval));
    }

    const aladinApi = getAladinApi();
    if (typeof aladinApi === 'undefined' || typeof aladinApi.aladin !== 'function') {
        throw new Error('Aladin Lite not loaded');
    }

    if (aladinApi.init && typeof aladinApi.init.then === 'function') {
        await aladinApi.init;
    }

}

function resolveFovOverlayDefinitions(options) {
    if (Array.isArray(options.fovOverlays) && options.fovOverlays.length > 0) {
        return options.fovOverlays
            .filter(overlay => overlay && overlay.widthDeg && overlay.heightDeg)
            .map(overlay => ({
                name: overlay.name || 'Equipment FOV',
                color: overlay.color || '#00FF00',
                centerRaHours: overlay.centerRaHours,
                centerDecDegrees: overlay.centerDecDegrees,
                widthDeg: overlay.widthDeg,
                heightDeg: overlay.heightDeg,
                rotation: overlay.rotation || 0
            }));
    }

    if (options.showFovOverlay && options.fovWidthDeg && options.fovHeightDeg) {
        return [{
            name: options.equipmentName || 'Equipment FOV',
            color: options.fovColor || '#00FF00',
            widthDeg: options.fovWidthDeg,
            heightDeg: options.fovHeightDeg,
            rotation: options.fovRotation || 0
        }];
    }

    return [];
}

function createFovOverlays(aladin, overlayDefinitions) {
    return overlayDefinitions.map(definition => {
        const aladinApi = getAladinApi();
        const overlay = aladinApi.graphicOverlay({ name: definition.name, color: definition.color });
        aladin.addOverlay(overlay);
        return overlay;
    });
}

function updateFovOverlays(overlays, overlayDefinitions, raDegrees, dec, visible) {
    if (!Array.isArray(overlays) || !Array.isArray(overlayDefinitions)) {
        return;
    }

    overlays.forEach((overlay, index) => {
        if (!visible) {
            overlay.removeAll();
            return;
        }

        const definition = overlayDefinitions[index];
        if (!definition) {
            overlay.removeAll();
            return;
        }

        const overlayRaDegrees = typeof definition.centerRaHours === 'number'
            ? definition.centerRaHours * 15
            : raDegrees;
        const overlayDec = typeof definition.centerDecDegrees === 'number'
            ? definition.centerDecDegrees
            : dec;

        updateFovOverlay(
            overlay,
            overlayRaDegrees,
            overlayDec,
            definition.widthDeg,
            definition.heightDeg,
            definition.rotation,
            definition.color,
            definition.name);
    });
}

function clearFovOverlays(overlays) {
    if (!Array.isArray(overlays)) {
        return;
    }

    overlays.forEach(overlay => {
        if (overlay) {
            overlay.removeAll();
        }
    });
}
