/**
 * Persistence Manager Module
 * Handles saving and loading game state and user preferences
 */
import { BaseModule } from './base-module.js';
import { moduleRegistry } from './module-registry.js';

class PersistenceManagerModule extends BaseModule {
    /**
     * Create a new persistence manager
     */
    constructor() {
        super('persistence-manager', 'Persistence Manager');
        this.storage = window.localStorage;
        this.stateKey = 'ai_fiction_state';
        this.prefsKey = 'ai_fiction_prefs';
        
        // Default preferences
        this.defaultPreferences = {
            tts: {
                enabled: false,
                provider: 'browser', // 'browser', 'kokoro', 'elevenlabs'
                voice: '',
                volume: 1.0
            },
            audio: {
                masterVolume: 1.0,
                musicVolume: 0.7,
                sfxVolume: 1.0
            },
            animation: {
                speed: 50, // 0-100 scale
                fastForwardKey: ' ' // Space key
            },
            accessibility: {
                highContrast: false,
                largerText: false
            }
        };
        
        // Current preferences (will be loaded from storage)
        this.preferences = { ...this.defaultPreferences };
    }
    
    /**
     * Initialize the module
     * @returns {Promise<boolean>} - Resolves with success status
     */
    async initialize() {
        try {
            // Test storage availability
            this.storage = this.getStorageObject();
            
            // Load preferences automatically
            this.loadPreferences();
            
            this.reportProgress(100, "Persistence manager ready");
            return true;
        } catch (error) {
            console.error("Error initializing persistence manager:", error);
            // Continue without persistence rather than failing
            return true;
        }
    }
    
    /**
     * Get the appropriate storage object, testing availability
     * @returns {Storage} - The storage object to use
     */
    getStorageObject() {
        try {
            // Test if localStorage is available
            if (window.localStorage) {
                const testKey = '__storage_test__';
                window.localStorage.setItem(testKey, testKey);
                window.localStorage.removeItem(testKey);
                return window.localStorage;
            }
        } catch (e) {
            console.warn('localStorage not available, using memory storage');
            // Create a memory-based storage fallback
            return this.createMemoryStorage();
        }
        
        console.warn('localStorage not available, using memory storage');
        return this.createMemoryStorage();
    }
    
    /**
     * Create a memory-based storage fallback
     * @returns {Object} - A storage-like object
     */
    createMemoryStorage() {
        const memoryStore = {};
        
        return {
            getItem: (key) => memoryStore[key] || null,
            setItem: (key, value) => {
                memoryStore[key] = String(value);
            },
            removeItem: (key) => {
                delete memoryStore[key];
            },
            clear: () => {
                Object.keys(memoryStore).forEach(key => {
                    delete memoryStore[key];
                });
            }
        };
    }
    
    /**
     * Save the current game state
     * @param {Object} state - The game state to save
     */
    saveState(state) {
        if (!this.storage) {
            console.warn('No storage available, game state not saved.');
            return false;
        }
        
        try {
            const stateString = JSON.stringify(state);
            this.storage.setItem(this.stateKey, stateString);
            console.log('Game state saved successfully.');
            return true;
        } catch (error) {
            console.error('Error saving game state:', error);
            return false;
        }
    }
    
    /**
     * Load the saved game state
     * @returns {Object|null} The loaded state or null if no state exists
     */
    loadState() {
        if (!this.storage) {
            console.warn('No storage available, cannot load game state.');
            return null;
        }
        
        try {
            const stateString = this.storage.getItem(this.stateKey);
            if (!stateString) {
                console.info('No saved game state found.');
                return null;
            }
            
            const state = JSON.parse(stateString);
            console.log('Game state loaded successfully.');
            return state;
        } catch (error) {
            console.error('Error loading game state:', error);
            return null;
        }
    }
    
    /**
     * Check if a saved game state exists
     * @returns {boolean} Whether a saved state exists
     */
    hasSavedState() {
        if (!this.storage) return false;
        return !!this.storage.getItem(this.stateKey);
    }
    
    /**
     * Delete the saved game state
     * @returns {boolean} Whether the state was successfully deleted
     */
    clearState() {
        if (!this.storage) return false;
        try {
            this.storage.removeItem(this.stateKey);
            console.log('Game state cleared.');
            return true;
        } catch (error) {
            console.error('Error clearing game state:', error);
            return false;
        }
    }
    
    /**
     * Save user preferences
     * @param {Object} [preferences] - Preferences to save (defaults to current preferences)
     * @returns {boolean} Whether preferences were successfully saved
     */
    savePreferences(preferences = null) {
        if (!this.storage) {
            console.warn('No storage available, preferences not saved.');
            return false;
        }
        
        // Use provided preferences or current preferences
        const prefsToSave = preferences || this.preferences;
        
        try {
            const prefsString = JSON.stringify(prefsToSave);
            this.storage.setItem(this.prefsKey, prefsString);
            console.log('Preferences saved successfully.');
            
            // Update current preferences
            if (preferences) {
                this.preferences = { ...this.preferences, ...preferences };
            }
            
            return true;
        } catch (error) {
            console.error('Error saving preferences:', error);
            return false;
        }
    }
    
    /**
     * Load user preferences
     * @returns {Object} The loaded preferences or default preferences if none exist
     */
    loadPreferences() {
        if (!this.storage) {
            console.warn('No storage available, using default preferences.');
            return { ...this.defaultPreferences };
        }
        
        try {
            const prefsString = this.storage.getItem(this.prefsKey);
            if (!prefsString) {
                console.info('No saved preferences found, using defaults.');
                this.preferences = { ...this.defaultPreferences };
                return this.preferences;
            }
            
            const loadedPrefs = JSON.parse(prefsString);
            
            // Merge with default preferences to ensure all fields exist
            this.preferences = this.mergeWithDefaults(loadedPrefs, this.defaultPreferences);
            
            console.log('Preferences loaded successfully.');
            return this.preferences;
        } catch (error) {
            console.error('Error loading preferences:', error);
            this.preferences = { ...this.defaultPreferences };
            return this.preferences;
        }
    }
    
    /**
     * Merge loaded preferences with default values to ensure all fields exist
     * @param {Object} loaded - The loaded preferences
     * @param {Object} defaults - The default preferences
     * @returns {Object} Merged preferences
     * @private
     */
    mergeWithDefaults(loaded, defaults) {
        const result = {};
        
        // Start with defaults
        for (const key in defaults) {
            if (typeof defaults[key] === 'object' && defaults[key] !== null && !Array.isArray(defaults[key])) {
                // Recurse for nested objects
                if (loaded && loaded[key]) {
                    result[key] = this.mergeWithDefaults(loaded[key], defaults[key]);
                } else {
                    result[key] = { ...defaults[key] };
                }
            } else {
                // Use loaded value if available, otherwise default
                result[key] = (loaded && loaded[key] !== undefined) ? loaded[key] : defaults[key];
            }
        }
        
        return result;
    }
    
    /**
     * Update specific preferences
     * @param {string} category - The preference category (e.g., 'tts', 'audio')
     * @param {string} setting - The specific setting name
     * @param {any} value - The new value
     * @param {boolean} [saveImmediately=true] - Whether to save immediately
     */
    updatePreference(category, setting, value, saveImmediately = true) {
        // Ensure the category exists
        if (!this.preferences[category]) {
            console.warn(`Preference category '${category}' doesn't exist.`);
            return false;
        }
        
        // Update the preference
        this.preferences[category][setting] = value;
        
        // Save if requested
        if (saveImmediately) {
            return this.savePreferences();
        }
        
        return true;
    }
    
    /**
     * Get a specific preference value
     * @param {string} category - The preference category
     * @param {string} setting - The specific setting name
     * @param {any} [defaultValue] - Default value if the preference doesn't exist
     * @returns {any} The preference value
     */
    getPreference(category, setting, defaultValue = null) {
        // Check if category exists
        if (!this.preferences[category]) {
            return defaultValue;
        }
        
        // Check if setting exists in category
        if (this.preferences[category].hasOwnProperty(setting)) {
            return this.preferences[category][setting];
        }
        
        return defaultValue;
    }
    
    /**
     * Reset preferences to defaults
     * @param {string} [category] - Optional category to reset (resets all if not specified)
     * @param {boolean} [saveImmediately=true] - Whether to save immediately
     */
    resetPreferences(category = null, saveImmediately = true) {
        if (category) {
            // Reset only specified category
            if (this.defaultPreferences[category]) {
                this.preferences[category] = { ...this.defaultPreferences[category] };
            }
        } else {
            // Reset all preferences
            this.preferences = { ...this.defaultPreferences };
        }
        
        // Save if requested
        if (saveImmediately) {
            return this.savePreferences();
        }
        
        return true;
    }
    
    /**
     * Get all preferences
     * @returns {Object} The current preferences
     */
    getAllPreferences() {
        return { ...this.preferences };
    }
}

// Create the singleton instance
const PersistenceManager = new PersistenceManagerModule();

// Register with the module registry
moduleRegistry.register(PersistenceManager);

// Export the module
export { PersistenceManager };

// Keep a reference in window for loader system
window.PersistenceManager = PersistenceManager;
