// modules/api-manager/StorageManager.js
import { Logger } from '../../core/logger.js';

/**
 * Storage APIs Manager - IndexedDB, Cache API, Web Locks, Broadcast Channel
 */
export class StorageManager {
    constructor(config = {}) {
        this.config = config;
        this.dbName = config.dbName || 'AppDatabase';
        this.dbVersion = config.dbVersion || 1;
        this.db = null;
        this.cache = null;
        this.channels = new Map();
        
        // Check API support
        this.support = {
            indexedDB: 'indexedDB' in window,
            cacheAPI: 'caches' in window,
            webLocks: 'locks' in navigator,
            broadcastChannel: 'BroadcastChannel' in window,
            localStorage: 'localStorage' in window,
            sessionStorage: 'sessionStorage' in window
        };
        
        Logger.info('[StorageManager] Initialized with support:', this.support);
        
        // Initialize databases
        this.initializeDB();
        this.initializeCache();
    }
    
    /**
     * Initialize IndexedDB
     */
    async initializeDB() {
        if (!this.support.indexedDB) {
            Logger.warn('[StorageManager] IndexedDB not supported');
            return;
        }
        
        try {
            const request = indexedDB.open(this.dbName, this.dbVersion);
            
            request.onerror = () => {
                Logger.error('[StorageManager] IndexedDB failed to open');
            };
            
            request.onupgradeneeded = (event) => {
                const db = event.target.result;
                
                // Create default object stores
                if (!db.objectStoreNames.contains('keyValue')) {
                    const store = db.createObjectStore('keyValue', { keyPath: 'key' });
                    store.createIndex('timestamp', 'timestamp', { unique: false });
                }
                
                if (!db.objectStoreNames.contains('cache')) {
                    db.createObjectStore('cache', { keyPath: 'key' });
                }
                
                if (!db.objectStoreNames.contains('files')) {
                    const fileStore = db.createObjectStore('files', { keyPath: 'id', autoIncrement: true });
                    fileStore.createIndex('name', 'name', { unique: false });
                    fileStore.createIndex('type', 'type', { unique: false });
                }
                
                Logger.info('[StorageManager] IndexedDB schema updated');
            };
            
            request.onsuccess = (event) => {
                this.db = event.target.result;
                Logger.info('[StorageManager] IndexedDB connected');
            };
            
        } catch (error) {
            Logger.error('[StorageManager] IndexedDB initialization failed:', error);
        }
    }
    
    /**
     * Initialize Cache API
     */
    async initializeCache() {
        if (!this.support.cacheAPI) {
            Logger.warn('[StorageManager] Cache API not supported');
            return;
        }
        
        try {
            this.cache = await caches.open(this.config.cacheName || 'app-cache-v1');
            Logger.info('[StorageManager] Cache API initialized');
        } catch (error) {
            Logger.error('[StorageManager] Cache API initialization failed:', error);
        }
    }
    
    /**
     * IndexedDB Operations
     */
    db = {
        // Set key-value data
        set: async (key, value, expiration = null) => {
            return new Promise((resolve, reject) => {
                if (!this.db) {
                    reject(new Error('IndexedDB not available'));
                    return;
                }
                
                const transaction = this.db.transaction(['keyValue'], 'readwrite');
                const store = transaction.objectStore('keyValue');
                
                const data = {
                    key,
                    value,
                    timestamp: Date.now(),
                    expiration: expiration ? Date.now() + expiration : null
                };
                
                const request = store.put(data);
                
                request.onsuccess = () => {
                    Logger.info(`[StorageManager] DB set: ${key}`);
                    resolve(data);
                };
                
                request.onerror = () => {
                    Logger.error(`[StorageManager] DB set failed: ${key}`);
                    reject(request.error);
                };
            });
        },
        
        // Get key-value data
        get: async (key) => {
            return new Promise((resolve, reject) => {
                if (!this.db) {
                    reject(new Error('IndexedDB not available'));
                    return;
                }
                
                const transaction = this.db.transaction(['keyValue'], 'readonly');
                const store = transaction.objectStore('keyValue');
                const request = store.get(key);
                
                request.onsuccess = () => {
                    const result = request.result;
                    
                    if (!result) {
                        resolve(null);
                        return;
                    }
                    
                    // Check expiration
                    if (result.expiration && Date.now() > result.expiration) {
                        this.db.delete(key); // Auto-cleanup expired data
                        resolve(null);
                        return;
                    }
                    
                    resolve(result.value);
                };
                
                request.onerror = () => {
                    Logger.error(`[StorageManager] DB get failed: ${key}`);
                    reject(request.error);
                };
            });
        },
        
        // Delete key
        delete: async (key) => {
            return new Promise((resolve, reject) => {
                if (!this.db) {
                    reject(new Error('IndexedDB not available'));
                    return;
                }
                
                const transaction = this.db.transaction(['keyValue'], 'readwrite');
                const store = transaction.objectStore('keyValue');
                const request = store.delete(key);
                
                request.onsuccess = () => {
                    Logger.info(`[StorageManager] DB deleted: ${key}`);
                    resolve(true);
                };
                
                request.onerror = () => {
                    reject(request.error);
                };
            });
        },
        
        // Get all keys
        keys: async () => {
            return new Promise((resolve, reject) => {
                if (!this.db) {
                    reject(new Error('IndexedDB not available'));
                    return;
                }
                
                const transaction = this.db.transaction(['keyValue'], 'readonly');
                const store = transaction.objectStore('keyValue');
                const request = store.getAllKeys();
                
                request.onsuccess = () => {
                    resolve(request.result);
                };
                
                request.onerror = () => {
                    reject(request.error);
                };
            });
        },
        
        // Clear all data
        clear: async () => {
            return new Promise((resolve, reject) => {
                if (!this.db) {
                    reject(new Error('IndexedDB not available'));
                    return;
                }
                
                const transaction = this.db.transaction(['keyValue'], 'readwrite');
                const store = transaction.objectStore('keyValue');
                const request = store.clear();
                
                request.onsuccess = () => {
                    Logger.info('[StorageManager] DB cleared');
                    resolve(true);
                };
                
                request.onerror = () => {
                    reject(request.error);
                };
            });
        },
        
        // Store files/blobs
        storeFile: async (name, file, metadata = {}) => {
            return new Promise((resolve, reject) => {
                if (!this.db) {
                    reject(new Error('IndexedDB not available'));
                    return;
                }
                
                const transaction = this.db.transaction(['files'], 'readwrite');
                const store = transaction.objectStore('files');
                
                const fileData = {
                    name,
                    file,
                    type: file.type,
                    size: file.size,
                    timestamp: Date.now(),
                    metadata
                };
                
                const request = store.add(fileData);
                
                request.onsuccess = () => {
                    Logger.info(`[StorageManager] File stored: ${name}`);
                    resolve({ id: request.result, ...fileData });
                };
                
                request.onerror = () => {
                    reject(request.error);
                };
            });
        },
        
        // Get file
        getFile: async (id) => {
            return new Promise((resolve, reject) => {
                if (!this.db) {
                    reject(new Error('IndexedDB not available'));
                    return;
                }
                
                const transaction = this.db.transaction(['files'], 'readonly');
                const store = transaction.objectStore('files');
                const request = store.get(id);
                
                request.onsuccess = () => {
                    resolve(request.result);
                };
                
                request.onerror = () => {
                    reject(request.error);
                };
            });
        }
    };
    
    /**
     * Cache API Operations
     */
    cache = {
        // Add request/response to cache
        add: async (request, response = null) => {
            if (!this.cache) {
                throw new Error('Cache API not available');
            }
            
            try {
                if (response) {
                    await this.cache.put(request, response);
                } else {
                    await this.cache.add(request);
                }
                Logger.info(`[StorageManager] Cache add: ${request}`);
            } catch (error) {
                Logger.error('[StorageManager] Cache add failed:', error);
                throw error;
            }
        },
        
        // Get from cache
        get: async (request) => {
            if (!this.cache) {
                throw new Error('Cache API not available');
            }
            
            try {
                const response = await this.cache.match(request);
                if (response) {
                    Logger.info(`[StorageManager] Cache hit: ${request}`);
                } else {
                    Logger.info(`[StorageManager] Cache miss: ${request}`);
                }
                return response;
            } catch (error) {
                Logger.error('[StorageManager] Cache get failed:', error);
                throw error;
            }
        },
        
        // Delete from cache
        delete: async (request) => {
            if (!this.cache) {
                throw new Error('Cache API not available');
            }
            
            try {
                const success = await this.cache.delete(request);
                if (success) {
                    Logger.info(`[StorageManager] Cache deleted: ${request}`);
                }
                return success;
            } catch (error) {
                Logger.error('[StorageManager] Cache delete failed:', error);
                throw error;
            }
        },
        
        // Get all cached requests
        keys: async () => {
            if (!this.cache) {
                throw new Error('Cache API not available');
            }
            
            try {
                return await this.cache.keys();
            } catch (error) {
                Logger.error('[StorageManager] Cache keys failed:', error);
                throw error;
            }
        },
        
        // Clear cache
        clear: async () => {
            if (!this.cache) {
                throw new Error('Cache API not available');
            }
            
            try {
                const keys = await this.cache.keys();
                await Promise.all(keys.map(key => this.cache.delete(key)));
                Logger.info('[StorageManager] Cache cleared');
            } catch (error) {
                Logger.error('[StorageManager] Cache clear failed:', error);
                throw error;
            }
        }
    };
    
    /**
     * Broadcast Channel for cross-tab communication
     */
    channel = {
        // Create or get channel
        create: (channelName, onMessage = null) => {
            if (!this.support.broadcastChannel) {
                Logger.warn('[StorageManager] BroadcastChannel not supported');
                return null;
            }
            
            if (this.channels.has(channelName)) {
                return this.channels.get(channelName);
            }
            
            const channel = new BroadcastChannel(channelName);
            
            if (onMessage) {
                channel.addEventListener('message', onMessage);
            }
            
            const channelWrapper = {
                name: channelName,
                channel,
                
                send: (data) => {
                    channel.postMessage({
                        data,
                        timestamp: Date.now(),
                        sender: 'current-tab'
                    });
                    Logger.info(`[StorageManager] Broadcast sent to ${channelName}`);
                },
                
                onMessage: (callback) => {
                    channel.addEventListener('message', (event) => {
                        callback(event.data);
                    });
                },
                
                close: () => {
                    channel.close();
                    this.channels.delete(channelName);
                    Logger.info(`[StorageManager] Channel closed: ${channelName}`);
                }
            };
            
            this.channels.set(channelName, channelWrapper);
            Logger.info(`[StorageManager] Channel created: ${channelName}`);
            
            return channelWrapper;
        },
        
        // Get existing channel
        get: (channelName) => {
            return this.channels.get(channelName) || null;
        },
        
        // Close channel
        close: (channelName) => {
            const channel = this.channels.get(channelName);
            if (channel) {
                channel.close();
            }
        },
        
        // Close all channels
        closeAll: () => {
            this.channels.forEach(channel => channel.close());
            this.channels.clear();
            Logger.info('[StorageManager] All channels closed');
        }
    };
    
    /**
     * Web Locks API for resource locking
     */
    locks = {
        // Acquire lock
        acquire: async (lockName, callback, options = {}) => {
            if (!this.support.webLocks) {
                Logger.warn('[StorageManager] Web Locks not supported, executing without lock');
                return await callback();
            }
            
            try {
                return await navigator.locks.request(lockName, options, async (lock) => {
                    Logger.info(`[StorageManager] Lock acquired: ${lockName}`);
                    const result = await callback(lock);
                    Logger.info(`[StorageManager] Lock released: ${lockName}`);
                    return result;
                });
            } catch (error) {
                Logger.error(`[StorageManager] Lock failed: ${lockName}`, error);
                throw error;
            }
        },
        
        // Query locks
        query: async () => {
            if (!this.support.webLocks) {
                return { held: [], pending: [] };
            }
            
            try {
                return await navigator.locks.query();
            } catch (error) {
                Logger.error('[StorageManager] Lock query failed:', error);
                throw error;
            }
        }
    };
    
    /**
     * Local/Session Storage helpers (with JSON support)
     */
    local = {
        set: (key, value, expiration = null) => {
            if (!this.support.localStorage) return false;
            
            try {
                const data = {
                    value,
                    timestamp: Date.now(),
                    expiration: expiration ? Date.now() + expiration : null
                };
                localStorage.setItem(key, JSON.stringify(data));
                return true;
            } catch (error) {
                Logger.error('[StorageManager] localStorage set failed:', error);
                return false;
            }
        },
        
        get: (key) => {
            if (!this.support.localStorage) return null;
            
            try {
                const item = localStorage.getItem(key);
                if (!item) return null;
                
                const data = JSON.parse(item);
                
                // Check expiration
                if (data.expiration && Date.now() > data.expiration) {
                    localStorage.removeItem(key);
                    return null;
                }
                
                return data.value;
            } catch (error) {
                Logger.error('[StorageManager] localStorage get failed:', error);
                return null;
            }
        },
        
        delete: (key) => {
            if (!this.support.localStorage) return false;
            localStorage.removeItem(key);
            return true;
        },
        
        clear: () => {
            if (!this.support.localStorage) return false;
            localStorage.clear();
            return true;
        },
        
        keys: () => {
            if (!this.support.localStorage) return [];
            return Object.keys(localStorage);
        }
    };
    
    session = {
        set: (key, value) => {
            if (!this.support.sessionStorage) return false;
            
            try {
                sessionStorage.setItem(key, JSON.stringify(value));
                return true;
            } catch (error) {
                Logger.error('[StorageManager] sessionStorage set failed:', error);
                return false;
            }
        },
        
        get: (key) => {
            if (!this.support.sessionStorage) return null;
            
            try {
                const item = sessionStorage.getItem(key);
                return item ? JSON.parse(item) : null;
            } catch (error) {
                Logger.error('[StorageManager] sessionStorage get failed:', error);
                return null;
            }
        },
        
        delete: (key) => {
            if (!this.support.sessionStorage) return false;
            sessionStorage.removeItem(key);
            return true;
        },
        
        clear: () => {
            if (!this.support.sessionStorage) return false;
            sessionStorage.clear();
            return true;
        }
    };
    
    /**
     * Smart caching with automatic expiration
     */
    smartCache = {
        set: async (key, value, options = {}) => {
            const {
                storage = 'indexedDB',
                expiration = null,
                fallback = true
            } = options;
            
            try {
                if (storage === 'indexedDB' && this.db) {
                    return await this.db.set(key, value, expiration);
                } else if (fallback) {
                    return this.local.set(key, value, expiration);
                }
            } catch (error) {
                if (fallback) {
                    return this.local.set(key, value, expiration);
                }
                throw error;
            }
        },
        
        get: async (key, options = {}) => {
            const { storage = 'indexedDB', fallback = true } = options;
            
            try {
                if (storage === 'indexedDB' && this.db) {
                    return await this.db.get(key);
                } else if (fallback) {
                    return this.local.get(key);
                }
            } catch (error) {
                if (fallback) {
                    return this.local.get(key);
                }
                throw error;
            }
        },
        
        delete: async (key, options = {}) => {
            const { storage = 'indexedDB', fallback = true } = options;
            
            try {
                if (storage === 'indexedDB' && this.db) {
                    await this.db.delete(key);
                }
                if (fallback) {
                    this.local.delete(key);
                }
            } catch (error) {
                if (fallback) {
                    this.local.delete(key);
                }
                throw error;
            }
        }
    };
    
    /**
     * Get storage usage statistics
     */
    async getStorageUsage() {
        const stats = {
            quota: 0,
            usage: 0,
            available: 0,
            percentage: 0
        };
        
        if ('storage' in navigator && 'estimate' in navigator.storage) {
            try {
                const estimate = await navigator.storage.estimate();
                stats.quota = estimate.quota || 0;
                stats.usage = estimate.usage || 0;
                stats.available = stats.quota - stats.usage;
                stats.percentage = stats.quota > 0 ? Math.round((stats.usage / stats.quota) * 100) : 0;
            } catch (error) {
                Logger.error('[StorageManager] Storage estimate failed:', error);
            }
        }
        
        return stats;
    }
    
    /**
     * Cleanup expired data
     */
    async cleanup() {
        Logger.info('[StorageManager] Starting cleanup...');
        
        try {
            // Cleanup IndexedDB expired entries
            if (this.db) {
                const transaction = this.db.transaction(['keyValue'], 'readwrite');
                const store = transaction.objectStore('keyValue');
                const index = store.index('timestamp');
                
                const request = index.openCursor();
                let cleaned = 0;
                
                request.onsuccess = (event) => {
                    const cursor = event.target.result;
                    if (cursor) {
                        const data = cursor.value;
                        if (data.expiration && Date.now() > data.expiration) {
                            cursor.delete();
                            cleaned++;
                        }
                        cursor.continue();
                    } else {
                        Logger.info(`[StorageManager] Cleanup completed: ${cleaned} expired entries removed`);
                    }
                };
            }
            
            // Cleanup localStorage expired entries
            if (this.support.localStorage) {
                const keys = Object.keys(localStorage);
                let localCleaned = 0;
                
                keys.forEach(key => {
                    try {
                        const item = localStorage.getItem(key);
                        const data = JSON.parse(item);
                        
                        if (data.expiration && Date.now() > data.expiration) {
                            localStorage.removeItem(key);
                            localCleaned++;
                        }
                    } catch (error) {
                        // Ignore non-JSON items
                    }
                });
                
                if (localCleaned > 0) {
                    Logger.info(`[StorageManager] LocalStorage cleanup: ${localCleaned} expired entries removed`);
                }
            }
            
        } catch (error) {
            Logger.error('[StorageManager] Cleanup failed:', error);
        }
    }
    
    /**
     * Get comprehensive storage status
     */
    async getStatus() {
        const usage = await this.getStorageUsage();
        
        return {
            support: this.support,
            usage,
            activeChannels: this.channels.size,
            dbConnected: !!this.db,
            cacheConnected: !!this.cache,
            channelNames: Array.from(this.channels.keys())
        };
    }
}