// Async IndexedDB with proper UI handling and user consent
window.asyncIndexedDb = {
    dbName: 'AstroManagerDSO',
    dbVersion: 1,
    isInitialized: false,
    hasUserConsent: false,

    // Check if persistent storage is supported and request permission
    async requestPersistentStorage() {
        if (!('storage' in navigator && 'persist' in navigator.storage)) {
            console.log('Persistent storage not supported');
            return false;
        }

        try {
            // Check current permission status
            const permission = await navigator.permissions.query({ name: 'persistent-storage' });
            
            if (permission.state === 'granted') {
                this.hasUserConsent = true;
                return true;
            }

            // Only request if not already denied
            if (permission.state !== 'denied') {
                const isPersistent = await navigator.storage.persist();
                this.hasUserConsent = isPersistent;
                return isPersistent;
            }

            return false;
        } catch (error) {
            console.warn('Failed to request persistent storage:', error);
            return false;
        }
    },

    // Show user-friendly consent dialog
    async showStorageConsentDialog() {
        return new Promise((resolve) => {
            const dialog = document.createElement('div');
            dialog.innerHTML = `
                <div style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; 
                           background: rgba(0,0,0,0.5); z-index: 10000; display: flex; 
                           align-items: center; justify-content: center;">
                    <div style="background: white; padding: 20px; border-radius: 8px; 
                               max-width: 400px; text-align: center; box-shadow: 0 4px 12px rgba(0,0,0,0.3);">
                        <h3>Enable Offline Database</h3>
                        <p>AstroManager can store astronomical data locally for faster access and offline use. 
                           This requires about 50MB of storage space.</p>
                        <div style="margin-top: 20px;">
                            <button id="consent-allow" style="background: #4CAF50; color: white; 
                                   border: none; padding: 10px 20px; margin: 5px; border-radius: 4px; cursor: pointer;">
                                Enable Offline Database
                            </button>
                            <button id="consent-deny" style="background: #f44336; color: white; 
                                   border: none; padding: 10px 20px; margin: 5px; border-radius: 4px; cursor: pointer;">
                                Skip for Now
                            </button>
                        </div>
                    </div>
                </div>
            `;

            document.body.appendChild(dialog);

            document.getElementById('consent-allow').onclick = async () => {
                document.body.removeChild(dialog);
                const granted = await this.requestPersistentStorage();
                resolve(granted);
            };

            document.getElementById('consent-deny').onclick = () => {
                document.body.removeChild(dialog);
                resolve(false);
            };
        });
    },

    // Non-blocking initialization with progress feedback
    async initializeAsync(progressCallback = null) {
        if (this.isInitialized) return true;

        try {
            // Step 1: Check/request storage permission
            if (progressCallback) progressCallback('Checking storage permissions...', 10);
            
            if (!this.hasUserConsent) {
                const consent = await this.showStorageConsentDialog();
                if (!consent) {
                    console.log('User declined persistent storage');
                    return false;
                }
            }

            // Step 2: Initialize database
            if (progressCallback) progressCallback('Initializing database...', 30);
            
            await this.openDatabase();
            
            if (progressCallback) progressCallback('Database ready', 100);
            this.isInitialized = true;
            return true;

        } catch (error) {
            console.error('Failed to initialize IndexedDB:', error);
            if (progressCallback) progressCallback('Database initialization failed', 0);
            return false;
        }
    },

    // Open database with proper error handling
    async openDatabase() {
        const openWithVersion = (version = undefined) => new Promise((resolve, reject) => {
            const request = version == null
                ? indexedDB.open(this.dbName)
                : indexedDB.open(this.dbName, version);
            
            request.onerror = () => reject(new Error('Failed to open database: ' + request.error));
            
            request.onsuccess = () => {
                resolve(request.result);
            };
            
            request.onupgradeneeded = (event) => {
                const db = event.target.result;
                
                // Create object stores
                if (!db.objectStoreNames.contains('dsoObjects')) {
                    const store = db.createObjectStore('dsoObjects', { keyPath: 'id' });
                    store.createIndex('identifier', 'identifier', { unique: false });
                    store.createIndex('constellation', 'constellation', { unique: false });
                    store.createIndex('baseType', 'baseType', { unique: false });
                    store.createIndex('magnitudeV', 'magnitudeV', { unique: false });
                }
                
                if (!db.objectStoreNames.contains('dsoMetadata')) {
                    db.createObjectStore('dsoMetadata', { keyPath: 'key' });
                }
            };
        });

        let db = await openWithVersion();
        const hasRequiredStores = db.objectStoreNames.contains('dsoObjects') && db.objectStoreNames.contains('dsoMetadata');
        if (!hasRequiredStores) {
            const repairedVersion = Math.max((db.version || this.dbVersion) + 1, this.dbVersion + 1);
            console.warn(`[AsyncIndexedDb] Missing required stores detected. Repairing schema by upgrading DB to version ${repairedVersion}.`);
            db.close();
            db = await openWithVersion(repairedVersion);
        }

        return db;
    },

    // Store data with chunking and progress updates
    async storeDataAsync(jsonData, progressCallback = null) {
        if (!this.isInitialized) {
            throw new Error('Database not initialized');
        }

        try {
            const objects = JSON.parse(jsonData);
            const totalObjects = objects.length;
            
            if (progressCallback) progressCallback(`Storing ${totalObjects} objects...`, 0);

            const db = await this.openDatabaseForTransaction();
            const transaction = db.transaction(['dsoObjects'], 'readwrite');
            const store = transaction.objectStore('dsoObjects');
            
            // Clear existing data first
            await this.clearStore(store);
            
            // Store in chunks to prevent UI blocking
            const chunkSize = 500; // Smaller chunks for better responsiveness
            let processed = 0;
            
            for (let i = 0; i < objects.length; i += chunkSize) {
                const chunk = objects.slice(i, i + chunkSize);
                
                // Store chunk
                for (const obj of chunk) {
                    // Ensure ID compatibility
                    if (obj.Id && !obj.id) obj.id = obj.Id;
                    if (!obj.id) throw new Error(`Object missing ID at index ${i + chunk.indexOf(obj)}`);
                    
                    store.add(obj);
                }
                
                processed += chunk.length;
                const progress = Math.round((processed / totalObjects) * 100);
                
                if (progressCallback) {
                    progressCallback(`Stored ${processed}/${totalObjects} objects`, progress);
                }
                
                // Yield control to prevent UI blocking
                await new Promise(resolve => setTimeout(resolve, 10));
            }
            
            // Wait for transaction to complete
            await new Promise((resolve, reject) => {
                transaction.oncomplete = resolve;
                transaction.onerror = () => reject(transaction.error);
            });
            
            db.close();
            
            if (progressCallback) progressCallback('Storage complete', 100);
            return true;
            
        } catch (error) {
            console.error('Error storing data:', error);
            if (progressCallback) progressCallback('Storage failed: ' + error.message, 0);
            throw error;
        }
    },

    async openDatabaseForTransaction() {
        return await this.openDatabase();
    },

    async clearStore(store) {
        return new Promise((resolve, reject) => {
            const clearRequest = store.clear();
            clearRequest.onsuccess = resolve;
            clearRequest.onerror = () => reject(clearRequest.error);
        });
    }
};

// Backward compatibility functions
window.initializeDsoIndexedDb = async function(progressCallback = null) {
    return await window.asyncIndexedDb.initializeAsync(progressCallback);
};

window.storeDsoObjects = async function(jsonData, progressCallback = null) {
    return await window.asyncIndexedDb.storeDataAsync(jsonData, progressCallback);
};
