/**
 * RSL Layout State Manager
 *
 * Manages layout state history, undo/redo operations, and preset management for RSL layouts.
 * Provides a comprehensive state management solution that works with both hand-authored HTML
 * and JSON-driven layouts, enabling temporal navigation and configuration persistence.
 *
 * @fileoverview State management with undo/redo, presets, and localStorage persistence
 * @version 1.0.0
 * @license MIT
 *
 * Key Features:
 * - Undo/redo functionality with configurable history size
 * - Preset save/load/delete operations
 * - localStorage persistence for history and presets
 * - DOM-based state capture and restore
 * - JSON schema integration for full layout reconstruction
 * - Event system for UI synchronization
 * - Works independently or alongside JSONLayoutEngine
 * - Automatic state diffing and incremental updates
 *
 * Usage:
 * // Standalone usage (HTML layouts)
 * RSL.StateManager.pushToHistory('Changed layout');
 * RSL.StateManager.undo();
 * RSL.StateManager.redo();
 *
 * // Preset management
 * RSL.StateManager.savePreset('My Layout', 'Optional description');
 * RSL.StateManager.loadPreset('My Layout');
 * RSL.StateManager.deletePreset('My Layout');
 *
 * // With JSON engine (full schema capture)
 * const jsonData = RSL.StateManager.toJSON({ includeSchema: true });
 * RSL.StateManager.fromJSON(jsonData);
 *
 * // Import/Export
 * const exportString = RSL.StateManager.exportState({ includeSchema: true });
 * RSL.StateManager.importState(exportString);
 *
 * Public API:
 * - RSL.StateManager.captureState(label) - Capture current layout state
 * - RSL.StateManager.restoreState(state) - Restore a state
 * - RSL.StateManager.pushToHistory(label) - Save state to undo/redo history
 * - RSL.StateManager.undo() - Undo last change
 * - RSL.StateManager.redo() - Redo last undone change
 * - RSL.StateManager.savePreset(name, description) - Save current state as preset
 * - RSL.StateManager.loadPreset(name) - Load a saved preset
 * - RSL.StateManager.deletePreset(name) - Delete a preset
 * - RSL.StateManager.getPresetNames() - Get all preset names
 * - RSL.StateManager.toJSON(options) - Export state as JSON object
 * - RSL.StateManager.fromJSON(json, options) - Import state from JSON
 * - RSL.StateManager.exportState(options) - Export as JSON string
 * - RSL.StateManager.importState(jsonString, options) - Import from JSON string
 * - RSL.StateManager.clearStorage() - Clear all saved data
 */

(function() {
    'use strict';

    /**
     * LayoutStateManager class
     * Manages state capture, history, presets, and persistence
     */
    class LayoutStateManager {
        constructor() {
            this.currentState = null;
            this.history = [];
            this.historyIndex = -1;
            this.maxHistorySize = 50;
            this.presets = new Map();
            this.storageKey = 'rsl-layout-state';

            // Initialize from localStorage if available
            this.loadFromStorage();
        }

        /**
         * Capture the current layout state across ALL slot-layouts on the page
         *
         * Extracts complete state information including breakpoints, gaps, item positioning,
         * visibility, classes, and custom properties. Works with both regular and nested layouts.
         *
         * @param {string} [label='Unnamed State'] - Descriptive label for this state
         * @returns {Object} State object with timestamp, label, and layout data
         *
         * @example
         * const state = RSL.StateManager.captureState('Before major changes');
         * console.log(state.layouts.length); // Number of layouts captured
         */
        captureState(label = 'Unnamed State') {
            const layouts = document.querySelectorAll('.slot-layout, .nested-slot-layout');
            const state = {
                timestamp: Date.now(),
                label: label,
                layouts: []
            };

            layouts.forEach((layout, index) => {
                const layoutState = {
                    id: layout.id || `layout-${index}`,
                    breakpoints: {
                        xs: layout.getAttribute('data-cols-xs'),
                        sm: layout.getAttribute('data-cols-sm'),
                        md: layout.getAttribute('data-cols-md'),
                        lg: layout.getAttribute('data-cols-lg'),
                        xl: layout.getAttribute('data-cols-xl'),
                        xxl: layout.getAttribute('data-cols-xxl')
                    },
                    gap: layout.getAttribute('data-gap'),
                    items: []
                };

                // Capture each item's state
                const items = layout.querySelectorAll(':scope > .slot-item, :scope > .nested-slot-item');
                items.forEach((item, itemIndex) => {
                    layoutState.items.push({
                        index: itemIndex,
                        id: item.id || `item-${itemIndex}`,
                        classes: Array.from(item.classList),
                        style: {
                            rowStart: item.style.getPropertyValue('--row-start'),
                            columnStart: item.style.getPropertyValue('--column-start'),
                            rowEnd: item.style.getPropertyValue('--row-end'),
                            columnEnd: item.style.getPropertyValue('--column-end')
                        },
                        visible: !item.classList.contains('hidden'),
                        order: item.style.order || 'auto'
                    });
                });

                state.layouts.push(layoutState);
            });

            return state;
        }

        /**
         * Restore a previously captured state
         *
         * Applies saved state to all layouts on the page, restoring breakpoints,
         * item positioning, visibility, and other properties. Triggers layout
         * recalculation after restoration.
         *
         * @param {Object} state - State object from captureState()
         * @returns {boolean} True if restoration succeeded, false otherwise
         *
         * @example
         * const success = RSL.StateManager.restoreState(previousState);
         * if (success) {
         *   console.log('Layout restored successfully');
         * }
         */
        restoreState(state) {
            if (!state || !state.layouts) return false;

            state.layouts.forEach(layoutState => {
                const layout = document.getElementById(layoutState.id) ||
                              document.querySelectorAll('.slot-layout, .nested-slot-layout')[
                                  parseInt(layoutState.id.split('-')[1])
                              ];

                if (!layout) return;

                // Restore breakpoint attributes
                Object.entries(layoutState.breakpoints).forEach(([bp, value]) => {
                    if (value !== null && value !== undefined) {
                        layout.setAttribute(`data-cols-${bp}`, value);
                    }
                });

                // Restore gap
                if (layoutState.gap) {
                    layout.setAttribute('data-gap', layoutState.gap);
                }

                // Restore item states
                const items = layout.querySelectorAll(':scope > .slot-item, :scope > .nested-slot-item');
                layoutState.items.forEach(itemState => {
                    const item = items[itemState.index];
                    if (!item) return;

                    // Restore positioning
                    if (itemState.style.rowStart) {
                        item.style.setProperty('--row-start', itemState.style.rowStart);
                    }
                    if (itemState.style.columnStart) {
                        item.style.setProperty('--column-start', itemState.style.columnStart);
                    }
                    if (itemState.style.rowEnd) {
                        item.style.setProperty('--row-end', itemState.style.rowEnd);
                    }
                    if (itemState.style.columnEnd) {
                        item.style.setProperty('--column-end', itemState.style.columnEnd);
                    }

                    // Restore visibility
                    if (itemState.visible) {
                        item.classList.remove('hidden');
                    } else {
                        item.classList.add('hidden');
                    }

                    // Restore order
                    if (itemState.order !== 'auto') {
                        item.style.order = itemState.order;
                    }
                });

                // Trigger recalculation
                if (typeof window.RSL !== 'undefined' && window.RSL.recalculateLayout) {
                    window.RSL.recalculateLayout(layout);
                }
            });

            this.currentState = state;
            this.emitStateChange();
            return true;
        }

        /**
         * Save current state to history (for undo/redo)
         *
         * Captures current layout state and adds it to the history stack.
         * Removes any future states if we're not at the end of history (branching).
         * Automatically limits history size to prevent memory issues.
         *
         * @param {string} label - Descriptive label for this history entry
         * @returns {Object} The captured state
         *
         * @example
         * RSL.StateManager.pushToHistory('Moved item to new position');
         * // Later: undo/redo available
         */
        pushToHistory(label) {
            const state = this.captureState(label);

            // Remove any states after current index (we're creating a new branch)
            this.history = this.history.slice(0, this.historyIndex + 1);

            // Add new state
            this.history.push(state);
            this.historyIndex++;

            // Limit history size
            if (this.history.length > this.maxHistorySize) {
                this.history.shift();
                this.historyIndex--;
            }

            this.saveToStorage();
            return state;
        }

        /**
         * Undo last change
         *
         * Steps back one position in history and restores that state.
         * Can be called multiple times to undo further back.
         *
         * @returns {boolean} True if undo succeeded, false if at history start
         *
         * @example
         * if (RSL.StateManager.undo()) {
         *   console.log('Undone successfully');
         * }
         */
        undo() {
            if (this.historyIndex > 0) {
                this.historyIndex--;
                this.restoreState(this.history[this.historyIndex]);
                return true;
            }
            return false;
        }

        /**
         * Redo last undone change
         *
         * Steps forward one position in history and restores that state.
         * Can be called multiple times to redo further forward.
         *
         * @returns {boolean} True if redo succeeded, false if at history end
         *
         * @example
         * if (RSL.StateManager.redo()) {
         *   console.log('Redone successfully');
         * }
         */
        redo() {
            if (this.historyIndex < this.history.length - 1) {
                this.historyIndex++;
                this.restoreState(this.history[this.historyIndex]);
                return true;
            }
            return false;
        }

        /**
         * Save a preset with a name
         *
         * Captures current state and saves it as a named preset. If JSON engine
         * is available, captures full schema for complete reconstruction. Otherwise,
         * saves state-only for HTML layouts.
         *
         * @param {string} name - Unique preset name
         * @param {string} [description=''] - Optional description
         * @returns {Object} The saved preset data
         *
         * @example
         * RSL.StateManager.savePreset('Mobile Layout', 'Optimized for mobile devices');
         */
        savePreset(name, description = '') {
            // Check if JSON engine is available - if so, save full schema + state
            if (window.RSL && window.RSL.JSONLayout) {
                const container = document.querySelector('.slot-layout')?.parentElement ||
                                document.querySelector('#layout-container') ||
                                document.body;

                try {
                    const fullData = this.toJSON({
                        includeSchema: true,
                        container: container
                    });
                    fullData.description = description;
                    fullData.label = name;
                    this.presets.set(name, fullData);
                    this.saveToStorage();
                    this.emitPresetChange();
                    return fullData;
                } catch (error) {
                    console.warn('Failed to save with schema, falling back to state-only:', error);
                }
            }

            // Fallback: save state only (for hand-authored HTML)
            const state = this.captureState(name);
            state.description = description;
            this.presets.set(name, state);
            this.saveToStorage();
            this.emitPresetChange();
            return state;
        }

        /**
         * Load a preset by name
         *
         * Restores a saved preset. If preset includes schema, reconstructs layout
         * from JSON. Otherwise, applies state to existing DOM elements.
         *
         * @param {string} name - Preset name to load
         * @returns {boolean} True if load succeeded, false if preset not found or error
         *
         * @example
         * if (RSL.StateManager.loadPreset('Mobile Layout')) {
         *   console.log('Preset loaded');
         * }
         */
        loadPreset(name) {
            const preset = this.presets.get(name);
            if (!preset) {
                console.error('Preset not found:', name);
                return false;
            }

            console.log('Loading preset:', name, preset);

            // Check if this is a full schema preset (has schema property)
            if (preset.schema && window.RSL && window.RSL.JSONLayout) {
                console.log('Restoring from schema');
                const container = document.querySelector('.slot-layout')?.parentElement ||
                                document.querySelector('#layout-container') ||
                                document.body;

                try {
                    // Clear the container first to avoid conflicts
                    console.log('Clearing container before loading preset');
                    container.innerHTML = '';

                    // Render the schema
                    window.RSL.JSONLayout.renderLayout(container, preset.schema);

                    // Then restore the state if present
                    if (preset.state) {
                        setTimeout(() => {
                            this.restoreState(preset.state);
                        }, 100);
                    }

                    this.pushToHistory(`Loaded preset: ${name}`);
                    return true;
                } catch (error) {
                    console.error('Failed to load preset with schema:', error);
                    return false;
                }
            }

            // Fallback: state-only preset (hand-authored HTML)
            console.log('Restoring from state only');
            const layouts = document.querySelectorAll('.slot-layout, .nested-slot-layout');
            console.log('Found layouts on page:', layouts.length);

            if (layouts.length === 0) {
                console.error('No layouts found on page. Cannot restore state-only preset.');
                alert('Cannot load this preset - it was saved without schema data. Please delete it and save a new one after importing a layout.');
                return false;
            }

            this.restoreState(preset);
            this.pushToHistory(`Loaded preset: ${name}`);
            return true;
        }

        /**
         * Delete a preset
         *
         * Removes a preset from storage and emits change event.
         *
         * @param {string} name - Preset name to delete
         * @returns {boolean} True if deletion succeeded, false if preset not found
         *
         * @example
         * if (RSL.StateManager.deletePreset('Old Layout')) {
         *   console.log('Preset deleted');
         * }
         */
        deletePreset(name) {
            const result = this.presets.delete(name);
            if (result) {
                this.saveToStorage();
                this.emitPresetChange();
            }
            return result;
        }

        /**
         * Get all preset names
         *
         * @returns {string[]} Array of preset names
         *
         * @example
         * const presets = RSL.StateManager.getPresetNames();
         * presets.forEach(name => console.log(name));
         */
        getPresetNames() {
            return Array.from(this.presets.keys());
        }

        /**
         * Export state as JSON (optionally including layout schema)
         *
         * Creates a JSON object containing current state and optionally the full
         * layout schema if JSONLayoutEngine is available. Useful for saving
         * complete layout configurations.
         *
         * @param {Object} [options={}] - Export options
         * @param {boolean} [options.includeSchema=false] - Include JSONLayout schema
         * @param {string|HTMLElement} [options.container=null] - Container to extract schema from
         * @returns {Object} JSON object with state and optional schema
         *
         * @example
         * const fullExport = RSL.StateManager.toJSON({
         *   includeSchema: true,
         *   container: '#app'
         * });
         */
        toJSON({ includeSchema = false, container = null } = {}) {
            const exportData = {
                version: 1,
                state: this.captureState('Export')
            };

            // Optionally include JSON schema if JSONLayoutEngine is available
            if (includeSchema && window.RSL && window.RSL.JSONLayout) {
                if (container) {
                    try {
                        exportData.schema = window.RSL.JSONLayout.buildFromDOM(container);
                    } catch (error) {
                        console.warn('Could not extract schema:', error);
                    }
                } else {
                    // Try to build from first layout found
                    const firstLayout = document.querySelector('.slot-layout');
                    if (firstLayout) {
                        try {
                            exportData.schema = window.RSL.JSONLayout.buildFromDOM(firstLayout.parentElement);
                        } catch (error) {
                            console.warn('Could not extract schema:', error);
                        }
                    }
                }
            }

            return exportData;
        }

        /**
         * Import state from JSON (optionally rebuilding layout from schema)
         *
         * Restores state from a JSON object. If JSON includes schema, rebuilds
         * the entire layout. Can be saved as a preset or applied immediately.
         *
         * @param {Object|string} json - JSON object or string to import
         * @param {Object} [options={}] - Import options
         * @param {boolean} [options.asPreset=false] - Save as preset instead of applying
         * @param {string} [options.presetName=''] - Name for preset if asPreset is true
         * @param {string|HTMLElement} [options.container=null] - Container to render schema into
         * @returns {boolean} True if import succeeded, false otherwise
         *
         * @example
         * const success = RSL.StateManager.fromJSON(jsonData, {
         *   container: '#app'
         * });
         */
        fromJSON(json, { asPreset = false, presetName = '', container = null } = {}) {
            try {
                // Parse if string
                const data = typeof json === 'string' ? JSON.parse(json) : json;

                // Check if JSON includes a schema
                if (data.schema && window.RSL && window.RSL.JSONLayout) {
                    // Rebuild layout from schema first
                    if (container) {
                        const containerEl = typeof container === 'string'
                            ? document.querySelector(container)
                            : container;

                        if (containerEl) {
                            window.RSL.JSONLayout.renderLayout(containerEl, data.schema);
                        }
                    } else {
                        console.warn('Schema found but no container specified. State may not apply correctly.');
                    }
                }

                // Handle preset vs. immediate application
                if (asPreset && presetName) {
                    this.presets.set(presetName, data.state);
                    this.saveToStorage();
                    this.emitPresetChange();
                } else if (data.state) {
                    this.restoreState(data.state);
                    this.pushToHistory('Imported state');
                }

                return true;
            } catch (error) {
                console.error('Failed to import from JSON:', error);
                return false;
            }
        }

        /**
         * Export state as JSON string
         *
         * Convenience method that calls toJSON() and serializes the result.
         *
         * @param {Object} [options={}] - Export options (same as toJSON)
         * @returns {string} Pretty-printed JSON string
         *
         * @example
         * const jsonString = RSL.StateManager.exportState({ includeSchema: true });
         * // Save to file or copy to clipboard
         */
        exportState(options = {}) {
            const data = this.toJSON(options);
            return JSON.stringify(data, null, 2);
        }

        /**
         * Import state from JSON string
         *
         * Convenience method that parses JSON and calls fromJSON().
         *
         * @param {string} jsonString - JSON string to import
         * @param {Object} [options={}] - Import options (same as fromJSON)
         * @returns {boolean} True if import succeeded, false otherwise
         *
         * @example
         * const success = RSL.StateManager.importState(jsonString, {
         *   container: '#app'
         * });
         */
        importState(jsonString, options = {}) {
            return this.fromJSON(jsonString, options);
        }

        /**
         * Persist to localStorage
         *
         * Saves current history and presets to localStorage for persistence
         * across page reloads. Automatically called by state-modifying methods.
         *
         * @private
         */
        saveToStorage() {
            try {
                const data = {
                    history: this.history,
                    historyIndex: this.historyIndex,
                    presets: Array.from(this.presets.entries())
                };
                localStorage.setItem(this.storageKey, JSON.stringify(data));
            } catch (error) {
                console.error('Failed to save to storage:', error);
            }
        }

        /**
         * Load from localStorage
         *
         * Restores history and presets from localStorage on initialization.
         * Automatically called by constructor.
         *
         * @private
         */
        loadFromStorage() {
            try {
                const data = JSON.parse(localStorage.getItem(this.storageKey));
                if (data) {
                    this.history = data.history || [];
                    this.historyIndex = data.historyIndex || -1;
                    this.presets = new Map(data.presets || []);
                }
            } catch (error) {
                console.error('Failed to load from storage:', error);
            }
        }

        /**
         * Clear all stored data
         *
         * Removes all history, presets, and current state. Also clears localStorage.
         * Cannot be undone - use with caution.
         *
         * @example
         * RSL.StateManager.clearStorage();
         * // All data cleared
         */
        clearStorage() {
            this.history = [];
            this.historyIndex = -1;
            this.presets.clear();
            this.currentState = null;
            localStorage.removeItem(this.storageKey);
            this.emitStateChange();
            this.emitPresetChange();
        }

        /**
         * Emit state change event
         *
         * Dispatches custom event for UI components to listen to state changes.
         *
         * @private
         */
        emitStateChange() {
            window.dispatchEvent(new CustomEvent('rsl:statechange', {
                detail: { state: this.currentState }
            }));
        }

        /**
         * Emit preset change event
         *
         * Dispatches custom event for UI components to listen to preset changes.
         *
         * @private
         */
        emitPresetChange() {
            window.dispatchEvent(new CustomEvent('rsl:presetchange', {
                detail: { presets: this.getPresetNames() }
            }));
        }
    }

    // Initialize global instance
    window.RSL = window.RSL || {};
    window.RSL.StateManager = new LayoutStateManager();

    // Emit ready event
    window.dispatchEvent(new CustomEvent('rsl:statemanager:ready'));

})();
