// DSO Worker Manager - Manages Web Worker lifecycle and provides API for Blazor
window.dsoWorkerManager = {
    worker: null,
    pendingCallbacks: new Map(),
    callbackId: 0,
    progressCallback: null,
    nearbyBatchCallback: null,
    isSupported: typeof Worker === 'function',
    initPromise: null,
    lastInitStrategy: null,
    lastInitError: null,
    lastWorkerUrl: null,

    getWorkerUrl() {
        const baseUrl = document.baseURI || window.location.origin + '/';
        return new URL('_content/Blazor.UI.RCL/js/dso-worker.js', baseUrl).href;
    },

    createWorker(workerUrl) {
        const attempts = [
            {
                strategy: 'direct',
                create: () => new Worker(workerUrl)
            },
            {
                strategy: 'blob-importscripts',
                create: () => {
                    const bootstrap = `importScripts(${JSON.stringify(workerUrl)});`;
                    const blob = new Blob([bootstrap], { type: 'application/javascript' });
                    const blobUrl = URL.createObjectURL(blob);
                    const worker = new Worker(blobUrl);
                    worker.__amBlobUrl = blobUrl;
                    return worker;
                }
            }
        ];

        const failures = [];

        for (const attempt of attempts) {
            try {
                const worker = attempt.create();
                return { worker, strategy: attempt.strategy };
            } catch (error) {
                failures.push(`${attempt.strategy}: ${error?.message || error}`);
            }
        }

        throw new Error(failures.join(' | '));
    },

    cleanupWorkerResources(worker) {
        if (worker?.__amBlobUrl) {
            URL.revokeObjectURL(worker.__amBlobUrl);
            delete worker.__amBlobUrl;
        }
    },
    
    // Initialize the worker
    init() {
        if (!this.isSupported) {
            console.warn('[DSO Worker] Web Workers not supported - will use main thread fallback');
            this.lastInitError = 'Worker API unavailable';
            return Promise.resolve(false);
        }
        
        if (this.worker) {
            console.log('[DSO Worker] Already initialized');
            return Promise.resolve(true);
        }
        
        // Return existing promise if initialization is in progress
        if (this.initPromise) {
            return this.initPromise;
        }
        
        this.initPromise = new Promise((resolve) => {
            let settled = false;

            const finish = (result, errorMessage = null) => {
                if (settled) {
                    return;
                }

                settled = true;

                if (!result) {
                    if (errorMessage) {
                        this.lastInitError = errorMessage;
                    }

                    if (this.worker) {
                        this.worker.terminate();
                        this.cleanupWorkerResources(this.worker);
                        this.worker = null;
                    }

                    this.initPromise = null;
                } else {
                    this.lastInitError = null;
                }

                resolve(result);
            };

            try {
                const workerUrl = this.getWorkerUrl();
                this.lastWorkerUrl = workerUrl;
                
                console.log('[DSO Worker] Creating worker from:', workerUrl);
                const workerInfo = this.createWorker(workerUrl);
                this.worker = workerInfo.worker;
                this.lastInitStrategy = workerInfo.strategy;
                console.log('[DSO Worker] Worker strategy:', workerInfo.strategy);
                
                // Set up ready handler
                const readyHandler = (e) => {
                    if (e.data && e.data.type === 'ready') {
                        console.log('[DSO Worker] Worker ready');
                        finish(true);
                    }
                };
                const errorHandler = (e) => {
                    const message = e?.message || 'Worker error';
                    console.error('[DSO Worker] Worker error:', message, e);
                    this.handleError(message);
                    finish(false, message);
                };

                this.worker.addEventListener('message', readyHandler);
                this.worker.addEventListener('error', errorHandler);
                
                this.worker.onmessage = (e) => this.handleMessage(e.data);
                
                // Timeout after 5 seconds
                setTimeout(() => {
                    if (!settled) {
                        console.error('[DSO Worker] Worker initialization timed out');
                        finish(false, 'Worker initialization timed out');
                    }
                }, 5000);
                
            } catch (error) {
                console.error('[DSO Worker] Failed to initialize:', error);
                finish(false, error?.message || 'Worker initialization failed');
            }
        });
        
        return this.initPromise;
    },
    
    // Handle messages from worker
    handleMessage(data) {
        const { type, action, ...rest } = data;
        
        switch (type) {
            case 'ready':
                console.log('DSO Worker ready');
                break;
                
            case 'progress':
                if (this.progressCallback) {
                    this.progressCallback.invokeMethodAsync('OnProgress', rest.message, rest.percent);
                }
                break;

            case 'nearbyBatch':
                if (this.nearbyBatchCallback) {
                    this.nearbyBatchCallback.invokeMethodAsync(
                        'OnNearbyBatch',
                        JSON.stringify(rest.batch || []),
                        rest.startIndex || 0,
                        rest.totalCount || 0);
                }
                break;
                
            case 'complete':
                const callback = this.pendingCallbacks.get(action);
                if (callback) {
                    callback.resolve(rest);
                    this.pendingCallbacks.delete(action);
                }
                break;
                
            case 'error':
                console.error('DSO Worker error:', rest.message);
                const errorCallback = this.pendingCallbacks.get(action);
                if (errorCallback) {
                    errorCallback.reject(new Error(rest.message));
                    this.pendingCallbacks.delete(action);
                }
                break;
        }
    },
    
    handleError(message) {
        // Reject all pending callbacks
        this.pendingCallbacks.forEach((callback) => {
            callback.reject(new Error(message));
        });
        this.pendingCallbacks.clear();
    },
    
    // Send action to worker and return promise
    sendAction(action, data = {}) {
        return new Promise((resolve, reject) => {
            if (!this.worker) {
                reject(new Error('Worker not initialized'));
                return;
            }
            
            this.pendingCallbacks.set(action, { resolve, reject });
            this.worker.postMessage({ action, data });
        });
    },
    
    // Set progress callback (Blazor DotNetObjectReference)
    setProgressCallback(dotNetRef) {
        this.progressCallback = dotNetRef;
    },
    
    // Clear progress callback
    clearProgressCallback() {
        this.progressCallback = null;
    },

    setNearbyBatchCallback(dotNetRef) {
        this.nearbyBatchCallback = dotNetRef;
    },

    clearNearbyBatchCallback() {
        this.nearbyBatchCallback = null;
    },
    
    // Terminate worker
    terminate() {
        if (this.worker) {
            this.worker.terminate();
            this.cleanupWorkerResources(this.worker);
            this.worker = null;
            this.pendingCallbacks.clear();
        }

        this.initPromise = null;
    }
};

// Blazor-callable functions
window.initDsoWorker = async function() {
    console.log('[DSO Worker] initDsoWorker called');
    const result = await window.dsoWorkerManager.init();
    console.log('[DSO Worker] initDsoWorker result:', result);
    return result;
};

window.dsoWorkerHasData = async function() {
    if (!window.dsoWorkerManager.isSupported || !window.dsoWorkerManager.worker) {
        // Fallback to main thread
        return await window.hasDsoObjects();
    }
    
    try {
        const result = await window.dsoWorkerManager.sendAction('hasData');
        return result.result;
    } catch {
        return false;
    }
};

window.dsoWorkerGetCount = async function() {
    if (!window.dsoWorkerManager.isSupported || !window.dsoWorkerManager.worker) {
        return await window.getDsoObjectCount();
    }
    
    try {
        const result = await window.dsoWorkerManager.sendAction('getCount');
        return result.result;
    } catch {
        return 0;
    }
};

window.dsoWorkerFetchAndStore = async function(apiUrl, version, progressRef) {
    console.log('[DSO Worker] dsoWorkerFetchAndStore called with apiUrl:', apiUrl);
    
    if (!window.dsoWorkerManager.isSupported) {
        console.warn('[DSO Worker] Web Workers not supported - using main thread (will be slow)');
        return -1; // Signal to use fallback
    }
    
    if (!window.dsoWorkerManager.worker) {
        console.log('[DSO Worker] Worker not initialized, initializing now...');
        const initialized = await window.dsoWorkerManager.init();
        if (!initialized) {
            console.error('[DSO Worker] Failed to initialize worker');
            return -1; // Signal to use fallback
        }
    }
    
    if (progressRef) {
        window.dsoWorkerManager.setProgressCallback(progressRef);
    }
    
    try {
        console.log('[DSO Worker] Sending fetchAndStore action to worker...');
        const result = await window.dsoWorkerManager.sendAction('fetchAndStore', { apiUrl, version });
        console.log('[DSO Worker] fetchAndStore completed, count:', result.count);
        return result.count || 0;
    } catch (error) {
        console.error('[DSO Worker] Worker fetch and store failed:', error);
        throw error;
    } finally {
        window.dsoWorkerManager.clearProgressCallback();
    }
};

window.dsoWorkerGetVersion = async function() {
    if (!window.dsoWorkerManager.isSupported || !window.dsoWorkerManager.worker) {
        return await window.getDsoVersion();
    }
    
    try {
        const result = await window.dsoWorkerManager.sendAction('getVersion');
        return result.result;
    } catch {
        return null;
    }
};

window.dsoWorkerSetVersion = async function(version) {
    if (!window.dsoWorkerManager.isSupported || !window.dsoWorkerManager.worker) {
        return await window.setDsoVersion(version);
    }
    
    try {
        await window.dsoWorkerManager.sendAction('setVersion', { version });
        return true;
    } catch {
        return false;
    }
};

window.isDsoWorkerSupported = function() {
    const supported = window.dsoWorkerManager.isSupported;
    console.log('[DSO Worker] isDsoWorkerSupported:', supported);
    return supported;
};

window.getDsoWorkerDiagnostics = function() {
    return {
        isSupported: window.dsoWorkerManager.isSupported,
        hasWorker: !!window.dsoWorkerManager.worker,
        lastInitStrategy: window.dsoWorkerManager.lastInitStrategy,
        lastInitError: window.dsoWorkerManager.lastInitError,
        lastWorkerUrl: window.dsoWorkerManager.lastWorkerUrl,
        baseUri: document.baseURI || null,
        userAgent: navigator.userAgent || null
    };
};

// Worker-based search - fully non-blocking
window.dsoWorkerSearch = async function(filterJson) {
    console.log('[DSO Worker] dsoWorkerSearch called');
    
    // Parse filter
    const filter = JSON.parse(filterJson);
    
    // Ensure worker is initialized
    if (!window.dsoWorkerManager.worker) {
        const initialized = await window.dsoWorkerManager.init();
        if (!initialized) {
            console.warn('[DSO Worker] Worker not available, falling back to main thread search');
            return await window.searchDsoObjects(filterJson);
        }
    }
    
    try {
        const result = await window.dsoWorkerManager.sendAction('search', { filter });
        console.log(`[DSO Worker] Search completed: ${result.result.totalCount} matches in ${result.result.elapsed}ms`);
        
        // Return JSON for C# deserialization
        return JSON.stringify(result.result);
    } catch (error) {
        console.error('[DSO Worker] Search failed, falling back:', error);
        // Fallback to main thread search
        return await window.searchDsoObjects(filterJson);
    }
};

// Worker-based search with observability filtering - fully non-blocking
window.dsoWorkerSearchWithObservability = async function(filterJson) {
    console.log('[DSO Worker] dsoWorkerSearchWithObservability called');
    
    // Parse filter
    const filter = JSON.parse(filterJson);
    
    // Ensure worker is initialized
    if (!window.dsoWorkerManager.worker) {
        const initialized = await window.dsoWorkerManager.init();
        if (!initialized) {
            console.warn('[DSO Worker] Worker not available for observability search');
            return null; // Signal to use C# fallback
        }
    }
    
    try {
        const result = await window.dsoWorkerManager.sendAction('searchWithObservability', { filter });
        console.log(`[DSO Worker] Observability search completed: ${result.result.totalCount} matches in ${result.result.elapsed}ms`);
        
        // Return JSON for C# deserialization
        return JSON.stringify(result.result);
    } catch (error) {
        console.error('[DSO Worker] Observability search failed:', error);
        return null; // Signal to use C# fallback
    }
};

window.dsoWorkerSearchNearbyStream = async function(filterJson, batchRef) {
    console.log('[DSO Worker] dsoWorkerSearchNearbyStream called');

    const filter = JSON.parse(filterJson);

    if (!window.dsoWorkerManager.worker) {
        const initialized = await window.dsoWorkerManager.init();
        if (!initialized) {
            console.warn('[DSO Worker] Worker not available for nearby streaming');
            return null;
        }
    }

    if (batchRef) {
        window.dsoWorkerManager.setNearbyBatchCallback(batchRef);
    }

    try {
        const result = await window.dsoWorkerManager.sendAction('searchNearbyStream', { filter });
        console.log(`[DSO Worker] Nearby streaming completed: ${result.result.totalCount} matches in ${result.result.elapsed}ms`);
        return JSON.stringify(result.result);
    } catch (error) {
        console.error('[DSO Worker] Nearby streaming failed:', error);
        return null;
    } finally {
        window.dsoWorkerManager.clearNearbyBatchCallback();
    }
};

// Worker-based chart data calculation - fully non-blocking
window.dsoWorkerCalculateChartData = async function(paramsJson) {
    console.log('[DSO Worker] dsoWorkerCalculateChartData called');
    
    // Parse params
    const params = JSON.parse(paramsJson);
    
    // Ensure worker is initialized
    if (!window.dsoWorkerManager.worker) {
        const initialized = await window.dsoWorkerManager.init();
        if (!initialized) {
            console.warn('[DSO Worker] Worker not available for chart calculation');
            return null; // Signal to use C# fallback
        }
    }
    
    try {
        const result = await window.dsoWorkerManager.sendAction('calculateChartData', { params });
        console.log(`[DSO Worker] Chart data calculated: ${result.result.dataPoints.length} points in ${result.result.elapsed}ms`);
        
        // Return JSON for C# deserialization
        return JSON.stringify(result.result);
    } catch (error) {
        console.error('[DSO Worker] Chart calculation failed:', error);
        return null; // Signal to use C# fallback
    }
};

// Worker-based batch chart data calculation for multiple DSOs - fully non-blocking
window.dsoWorkerCalculateBatchChartData = async function(paramsJson) {
    console.log('[DSO Worker] dsoWorkerCalculateBatchChartData called');
    
    // Parse params
    const params = JSON.parse(paramsJson);
    
    // Ensure worker is initialized
    if (!window.dsoWorkerManager.worker) {
        const initialized = await window.dsoWorkerManager.init();
        if (!initialized) {
            console.warn('[DSO Worker] Worker not available for batch chart calculation');
            return null; // Signal to use C# fallback
        }
    }
    
    try {
        const result = await window.dsoWorkerManager.sendAction('calculateBatchChartData', { params });
        console.log(`[DSO Worker] Batch chart data calculated: ${Object.keys(result.result.results).length} DSOs in ${result.result.elapsed}ms`);
        
        // Return JSON for C# deserialization
        return JSON.stringify(result.result);
    } catch (error) {
        console.error('[DSO Worker] Batch chart calculation failed:', error);
        return null; // Signal to use C# fallback
    }
};
