/**
 * Form Auto-Save System
 * 
 * Automatically saves form data to localStorage and restores it when the user
 * returns to the page. Helps prevent data loss from browser crashes, accidental
 * navigation, network issues, or other interruptions.
 * 
 * Features:
 * - Automatic saving every 30 seconds
 * - Smart field change detection
 * - Secure storage (excludes passwords and sensitive data)
 * - Configurable retention period (default 24 hours)
 * - Visual indicators when data is saved/restored
 * - Privacy-conscious (excludes honeypot fields)
 * - Multiple form support
 * - Graceful cleanup of expired drafts
 * 
 * Usage:
 * import { FormAutoSave } from './modules/form-autosave.js';
 * 
 * // Initialize for specific form
 * const autosave = new FormAutoSave({
 *     formSelector: '#contact-form',
 *     storageKey: 'contact_form_draft'
 * });
 * 
 * // Or auto-initialize all forms
 * FormAutoSave.initializeAll();
 */

export class FormAutoSave {

    /**
     * Default configuration
     */
    static DEFAULT_CONFIG = {
        formSelector: 'form[data-autosave]',
        saveInterval: 30000, // 30 seconds
        retentionPeriod: 24 * 60 * 60 * 1000, // 24 hours
        storagePrefix: 'form_draft_',
        enableVisualFeedback: true,
        enableConsoleLogging: true,
        
        // Security settings
        excludeFields: [
            'input[type="password"]',
            'input[type="hidden"][name="_token"]',
            'input[type="hidden"][name="_form_id"]',
            'input[name*="password"]',
            'input[name*="confirm"]',
            'input[name*="honeypot"]',
            'input[name="email_confirm"]',
            'input[name="website_url"]',
            'input[name="user_name"]',
            'input[name="company_name"]'
        ],
        
        // Fields that trigger immediate save (important fields)
        immediateFields: [
            'textarea',
            'input[type="email"]',
            'input[type="text"]',
            'select'
        ],
        
        // Cleanup settings
        maxDraftAge: 7 * 24 * 60 * 60 * 1000, // 7 days max storage
        cleanupOnInit: true
    };

    /**
     * @param {Object} config Configuration options
     */
    constructor(config = {}) {
        this.config = { ...FormAutoSave.DEFAULT_CONFIG, ...config };
        this.form = null;
        this.storageKey = null;
        this.saveTimer = null;
        this.lastSaveTime = null;
        this.hasChanges = false;
        this.isInitialized = false;
        this.fieldValues = new Map();

        this.log('FormAutoSave initializing', this.config);
        
        // Initialize the form
        this.initialize();
    }

    /**
     * Initialize the autosave system for the form
     */
    initialize() {
        // Find the form
        this.form = document.querySelector(this.config.formSelector);
        
        if (!this.form) {
            this.log('Form not found with selector:', this.config.formSelector);
            return;
        }

        // Generate storage key based on form or use provided key
        this.storageKey = this.config.storageKey || 
            this.config.storagePrefix + this.generateFormId();

        this.log('Form found, storage key:', this.storageKey);

        // Cleanup old drafts if enabled
        if (this.config.cleanupOnInit) {
            this.cleanupExpiredDrafts();
        }

        // Setup event listeners
        this.setupEventListeners();

        // Store initial field values
        this.storeInitialValues();

        // Restore saved data
        this.restoreDraft();

        // Start periodic saving
        this.startAutoSave();

        this.isInitialized = true;
        this.log('FormAutoSave initialized successfully');
        
        // Show status if enabled
        if (this.config.enableVisualFeedback) {
            this.showStatus('Auto-save enabled', 'info', 3000);
        }
    }

    /**
     * Generate a unique form identifier
     */
    generateFormId() {
        // Try to get form ID from various sources
        const formId = this.form.id || 
                      this.form.getAttribute('data-form-id') ||
                      this.form.querySelector('input[name="_form_id"]')?.value ||
                      'form_' + Date.now();
        
        return formId.replace(/[^a-zA-Z0-9_-]/g, '_');
    }

    /**
     * Setup form event listeners
     */
    setupEventListeners() {
        // Listen for all input changes
        this.form.addEventListener('input', (e) => {
            this.onFieldChange(e);
        });

        this.form.addEventListener('change', (e) => {
            this.onFieldChange(e);
        });

        // Listen for form submission to clear draft
        this.form.addEventListener('submit', () => {
            this.onFormSubmit();
        });

        // Save on page unload
        window.addEventListener('beforeunload', () => {
            if (this.hasChanges) {
                this.saveDraft();
            }
        });

        // Handle page visibility changes
        document.addEventListener('visibilitychange', () => {
            if (document.hidden && this.hasChanges) {
                this.saveDraft();
            }
        });
    }

    /**
     * Store initial field values to detect changes
     */
    storeInitialValues() {
        const fields = this.getFormFields();
        
        fields.forEach(field => {
            const key = this.getFieldKey(field);
            const value = this.getFieldValue(field);
            this.fieldValues.set(key, value);
        });
        
        this.log(`Stored initial values for ${fields.length} fields`);
    }

    /**
     * Handle field value changes
     */
    onFieldChange(event) {
        const field = event.target;
        
        // Skip excluded fields
        if (this.isFieldExcluded(field)) {
            return;
        }

        const key = this.getFieldKey(field);
        const newValue = this.getFieldValue(field);
        const oldValue = this.fieldValues.get(key);

        // Check if value actually changed
        if (newValue !== oldValue) {
            this.fieldValues.set(key, newValue);
            this.hasChanges = true;

            this.log(`Field changed: ${key} = "${newValue}"`);

            // Save immediately for important fields
            if (this.isImmediateField(field)) {
                this.saveDraft();
            }
        }
    }

    /**
     * Handle form submission
     */
    onFormSubmit() {
        this.log('Form submitted, clearing draft');
        this.clearDraft();
        this.stopAutoSave();
        
        if (this.config.enableVisualFeedback) {
            this.showStatus('Form submitted, draft cleared', 'success', 2000);
        }
    }

    /**
     * Start periodic auto-save
     */
    startAutoSave() {
        if (this.saveTimer) {
            return;
        }

        this.saveTimer = setInterval(() => {
            if (this.hasChanges) {
                this.saveDraft();
            }
        }, this.config.saveInterval);

        this.log(`Auto-save started, interval: ${this.config.saveInterval}ms`);
    }

    /**
     * Stop periodic auto-save
     */
    stopAutoSave() {
        if (this.saveTimer) {
            clearInterval(this.saveTimer);
            this.saveTimer = null;
            this.log('Auto-save stopped');
        }
    }

    /**
     * Save current form data as draft
     */
    saveDraft() {
        if (!this.form || !this.hasChanges) {
            return;
        }

        try {
            const formData = this.extractFormData();
            
            const draft = {
                data: formData,
                timestamp: Date.now(),
                formId: this.generateFormId(),
                url: window.location.href,
                version: '1.0'
            };

            localStorage.setItem(this.storageKey, JSON.stringify(draft));
            
            this.lastSaveTime = new Date();
            this.hasChanges = false;
            
            this.log('Draft saved', {
                fields: Object.keys(formData).length,
                size: JSON.stringify(draft).length + ' chars'
            });

            if (this.config.enableVisualFeedback) {
                this.showStatus('Draft saved', 'success', 1500);
            }

        } catch (error) {
            console.error('Failed to save form draft:', error);
            
            if (this.config.enableVisualFeedback) {
                this.showStatus('Failed to save draft', 'error', 3000);
            }
        }
    }

    /**
     * Restore draft data to form
     */
    restoreDraft() {
        try {
            const draftJson = localStorage.getItem(this.storageKey);
            
            if (!draftJson) {
                this.log('No draft found');
                return;
            }

            const draft = JSON.parse(draftJson);
            
            // Check if draft is expired
            if (this.isDraftExpired(draft)) {
                this.log('Draft expired, removing');
                localStorage.removeItem(this.storageKey);
                return;
            }

            // Check if draft is from same form/URL (optional)
            if (draft.url && draft.url !== window.location.href) {
                this.log('Draft from different URL, skipping restore');
                return;
            }

            // Restore form data
            this.restoreFormData(draft.data);
            
            const age = this.formatDuration(Date.now() - draft.timestamp);
            this.log(`Draft restored (age: ${age})`, draft.data);

            if (this.config.enableVisualFeedback) {
                this.showStatus(`Draft restored from ${age} ago`, 'info', 4000);
            }

        } catch (error) {
            console.error('Failed to restore draft:', error);
            // Remove corrupted draft
            localStorage.removeItem(this.storageKey);
        }
    }

    /**
     * Extract form data (excluding sensitive fields)
     */
    extractFormData() {
        const fields = this.getFormFields();
        const data = {};

        fields.forEach(field => {
            if (!this.isFieldExcluded(field)) {
                const key = this.getFieldKey(field);
                const value = this.getFieldValue(field);
                
                if (value !== null && value !== undefined && value !== '') {
                    data[key] = value;
                }
            }
        });

        return data;
    }

    /**
     * Restore data to form fields
     */
    restoreFormData(data) {
        let restoredCount = 0;

        Object.entries(data).forEach(([key, value]) => {
            const field = this.findFieldByKey(key);
            
            if (field && !this.isFieldExcluded(field)) {
                this.setFieldValue(field, value);
                this.fieldValues.set(key, value);
                restoredCount++;
            }
        });

        this.log(`Restored ${restoredCount} field values`);
        
        // Trigger change events for any listeners
        const fields = this.getFormFields();
        fields.forEach(field => {
            if (!this.isFieldExcluded(field)) {
                field.dispatchEvent(new Event('change', { bubbles: true }));
            }
        });

        return restoredCount;
    }

    /**
     * Get all form fields
     */
    getFormFields() {
        return Array.from(this.form.querySelectorAll(
            'input:not([type="submit"]):not([type="button"]):not([type="reset"]), ' +
            'textarea, select'
        ));
    }

    /**
     * Check if field should be excluded from saving
     */
    isFieldExcluded(field) {
        return this.config.excludeFields.some(selector => 
            field.matches(selector)
        );
    }

    /**
     * Check if field should trigger immediate save
     */
    isImmediateField(field) {
        return this.config.immediateFields.some(selector => 
            field.matches(selector)
        );
    }

    /**
     * Generate unique key for field
     */
    getFieldKey(field) {
        return field.name || field.id || `field_${field.type}_${Date.now()}`;
    }

    /**
     * Get field value based on field type
     */
    getFieldValue(field) {
        switch (field.type) {
            case 'checkbox':
                return field.checked;
            case 'radio':
                return field.checked ? field.value : null;
            case 'file':
                return null; // Don't save file inputs
            default:
                return field.value;
        }
    }

    /**
     * Set field value based on field type
     */
    setFieldValue(field, value) {
        switch (field.type) {
            case 'checkbox':
                field.checked = Boolean(value);
                break;
            case 'radio':
                field.checked = (field.value === value);
                break;
            case 'file':
                // Can't restore file inputs
                break;
            default:
                field.value = value;
                break;
        }
    }

    /**
     * Find field by key
     */
    findFieldByKey(key) {
        return this.form.querySelector(`[name="${key}"], #${key}`);
    }

    /**
     * Check if draft has expired
     */
    isDraftExpired(draft) {
        const age = Date.now() - draft.timestamp;
        return age > this.config.retentionPeriod;
    }

    /**
     * Clear the current draft
     */
    clearDraft() {
        localStorage.removeItem(this.storageKey);
        this.hasChanges = false;
        this.log('Draft cleared');
    }

    /**
     * Cleanup all expired drafts
     */
    cleanupExpiredDrafts() {
        let cleaned = 0;
        const prefix = this.config.storagePrefix;

        for (let i = localStorage.length - 1; i >= 0; i--) {
            const key = localStorage.key(i);
            
            if (key && key.startsWith(prefix)) {
                try {
                    const draft = JSON.parse(localStorage.getItem(key));
                    const age = Date.now() - draft.timestamp;
                    
                    if (age > this.config.maxDraftAge) {
                        localStorage.removeItem(key);
                        cleaned++;
                    }
                } catch (error) {
                    // Remove corrupted entries
                    localStorage.removeItem(key);
                    cleaned++;
                }
            }
        }

        if (cleaned > 0) {
            this.log(`Cleaned up ${cleaned} expired drafts`);
        }
    }

    /**
     * Format duration for human reading
     */
    formatDuration(ms) {
        const seconds = Math.floor(ms / 1000);
        const minutes = Math.floor(seconds / 60);
        const hours = Math.floor(minutes / 60);
        
        if (hours > 0) {
            return `${hours}h ${minutes % 60}m`;
        } else if (minutes > 0) {
            return `${minutes}m`;
        } else {
            return `${seconds}s`;
        }
    }

    /**
     * Show visual status message
     */
    showStatus(message, type = 'info', duration = 3000) {
        // Create or update status element
        let statusEl = document.getElementById('form-autosave-status');
        
        if (!statusEl) {
            statusEl = document.createElement('div');
            statusEl.id = 'form-autosave-status';
            statusEl.style.cssText = `
                position: fixed;
                bottom: 20px;
                right: 20px;
                padding: 8px 12px;
                border-radius: 4px;
                font-size: 12px;
                z-index: 9999;
                max-width: 250px;
                box-shadow: 0 2px 8px rgba(0,0,0,0.1);
                transition: opacity 0.3s ease;
                font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            `;
            document.body.appendChild(statusEl);
        }

        statusEl.textContent = message;
        statusEl.className = `autosave-status-${type}`;
        
        const styles = {
            info: 'background: #e3f2fd; color: #1565c0; border: 1px solid #bbdefb;',
            success: 'background: #e8f5e8; color: #2e7d32; border: 1px solid #c8e6c9;',
            error: 'background: #ffebee; color: #c62828; border: 1px solid #ffcdd2;'
        };
        
        statusEl.style.cssText += styles[type] || styles.info;
        statusEl.style.opacity = '1';

        setTimeout(() => {
            if (statusEl) {
                statusEl.style.opacity = '0';
                setTimeout(() => {
                    if (statusEl && statusEl.parentNode) {
                        statusEl.parentNode.removeChild(statusEl);
                    }
                }, 300);
            }
        }, duration);
    }

    /**
     * Log messages if console logging is enabled
     */
    log(message, data = null) {
        if (this.config.enableConsoleLogging) {
            const timestamp = new Date().toLocaleTimeString();
            const prefix = `[${timestamp}] FormAutoSave`;
            
            if (data) {
                console.log(`${prefix}: ${message}`, data);
            } else {
                console.log(`${prefix}: ${message}`);
            }
        }
    }

    /**
     * Get current status
     */
    getStatus() {
        return {
            isInitialized: this.isInitialized,
            formId: this.generateFormId(),
            storageKey: this.storageKey,
            hasChanges: this.hasChanges,
            lastSaveTime: this.lastSaveTime,
            fieldCount: this.fieldValues.size,
            draftExists: !!localStorage.getItem(this.storageKey)
        };
    }

    /**
     * Manual save (for debugging/testing)
     */
    forceSave() {
        this.hasChanges = true;
        this.saveDraft();
    }

    /**
     * Destroy the autosave instance
     */
    destroy() {
        this.stopAutoSave();
        this.isInitialized = false;
        this.log('FormAutoSave destroyed');
    }

    /**
     * Static method to initialize all forms with autosave
     */
    static initializeAll() {
        const forms = document.querySelectorAll('form[data-autosave], form:has(input[name="_token"])');
        const instances = [];

        forms.forEach((form, index) => {
            const formId = form.id || 
                          form.getAttribute('data-form-id') || 
                          form.querySelector('input[name="_form_id"]')?.value ||
                          `form_${index}`;

            const instance = new FormAutoSave({
                formSelector: `#${form.id || 'form_' + index}`,
                storageKey: `form_draft_${formId}`
            });

            if (!form.id) {
                form.id = `form_${index}`;
            }

            instances.push(instance);
        });

        console.log(`FormAutoSave: Initialized for ${instances.length} forms`);
        return instances;
    }
}

// Export for manual usage
export default FormAutoSave;