/**
 * Accessibility Manager for LiveComponents
 *
 * Manages accessibility features for dynamic content updates:
 * - ARIA live regions for screen reader announcements
 * - Focus management with data-lc-keep-focus attribute
 * - Keyboard navigation preservation
 * - Screen reader-friendly update notifications
 *
 * WCAG 2.1 Compliance:
 * - 4.1.3 Status Messages (Level AA)
 * - 2.4.3 Focus Order (Level A)
 * - 2.1.1 Keyboard (Level A)
 */

export class AccessibilityManager {
    constructor() {
        /**
         * ARIA live region element for announcements
         * @type {HTMLElement|null}
         */
        this.liveRegion = null;

        /**
         * Component-specific live regions
         * Map<componentId, HTMLElement>
         */
        this.componentLiveRegions = new Map();

        /**
         * Focus tracking for restoration
         * Map<componentId, FocusState>
         */
        this.focusStates = new Map();

        /**
         * Announcement queue for throttling
         * @type {Array<{message: string, priority: string}>}
         */
        this.announcementQueue = [];

        /**
         * Announcement throttle timer
         * @type {number|null}
         */
        this.announceTimer = null;

        /**
         * Throttle delay in milliseconds
         * @type {number}
         */
        this.throttleDelay = 500;
    }

    /**
     * Initialize accessibility features
     *
     * Creates global live region and sets up initial state.
     */
    initialize() {
        // Create global live region if not exists
        if (!this.liveRegion) {
            this.liveRegion = this.createLiveRegion('livecomponent-announcer', 'polite');
            document.body.appendChild(this.liveRegion);
        }

        console.log('[AccessibilityManager] Initialized with ARIA live regions');
    }

    /**
     * Create ARIA live region element
     *
     * @param {string} id - Element ID
     * @param {string} politeness - ARIA politeness level (polite|assertive)
     * @returns {HTMLElement} Live region element
     */
    createLiveRegion(id, politeness = 'polite') {
        const region = document.createElement('div');
        region.id = id;
        region.setAttribute('role', 'status');
        region.setAttribute('aria-live', politeness);
        region.setAttribute('aria-atomic', 'true');
        region.className = 'sr-only'; // Screen reader only styling

        // Add screen reader only styles
        region.style.position = 'absolute';
        region.style.left = '-10000px';
        region.style.width = '1px';
        region.style.height = '1px';
        region.style.overflow = 'hidden';

        return region;
    }

    /**
     * Create component-specific live region
     *
     * Each component can have its own live region for isolated announcements.
     *
     * @param {string} componentId - Component identifier
     * @param {HTMLElement} container - Component container element
     * @param {string} politeness - ARIA politeness level
     * @returns {HTMLElement} Component live region
     */
    createComponentLiveRegion(componentId, container, politeness = 'polite') {
        // Check if already exists
        let liveRegion = this.componentLiveRegions.get(componentId);

        if (!liveRegion) {
            liveRegion = this.createLiveRegion(`livecomponent-${componentId}-announcer`, politeness);
            container.appendChild(liveRegion);
            this.componentLiveRegions.set(componentId, liveRegion);
        }

        return liveRegion;
    }

    /**
     * Announce update to screen readers
     *
     * Uses ARIA live regions to announce updates without stealing focus.
     * Supports throttling to prevent announcement spam.
     *
     * @param {string} message - Message to announce
     * @param {string} priority - Priority level (polite|assertive)
     * @param {string|null} componentId - Optional component-specific announcement
     */
    announce(message, priority = 'polite', componentId = null) {
        // Add to queue
        this.announcementQueue.push({ message, priority, componentId });

        // Throttle announcements
        if (this.announceTimer) {
            clearTimeout(this.announceTimer);
        }

        this.announceTimer = setTimeout(() => {
            this.flushAnnouncements();
        }, this.throttleDelay);
    }

    /**
     * Flush announcement queue
     *
     * Processes queued announcements and clears the queue.
     */
    flushAnnouncements() {
        if (this.announcementQueue.length === 0) return;

        // Get most recent announcement (others are outdated)
        const announcement = this.announcementQueue[this.announcementQueue.length - 1];
        this.announcementQueue = [];

        // Determine target live region
        let liveRegion = this.liveRegion;

        if (announcement.componentId) {
            const componentRegion = this.componentLiveRegions.get(announcement.componentId);
            if (componentRegion) {
                liveRegion = componentRegion;
            }
        }

        if (!liveRegion) {
            console.warn('[AccessibilityManager] No live region available for announcement');
            return;
        }

        // Update politeness if needed
        if (announcement.priority === 'assertive') {
            liveRegion.setAttribute('aria-live', 'assertive');
        } else {
            liveRegion.setAttribute('aria-live', 'polite');
        }

        // Clear and set new message
        liveRegion.textContent = '';

        // Use setTimeout to ensure screen reader picks up the change
        setTimeout(() => {
            liveRegion.textContent = announcement.message;
        }, 100);

        console.log(`[AccessibilityManager] Announced: "${announcement.message}" (${announcement.priority})`);
    }

    /**
     * Capture focus state before update
     *
     * Saves current focus state for potential restoration after update.
     *
     * @param {string} componentId - Component identifier
     * @param {HTMLElement} container - Component container element
     * @returns {FocusState} Focus state object
     */
    captureFocusState(componentId, container) {
        const activeElement = document.activeElement;

        // Check if focus is within container
        if (!activeElement || !container.contains(activeElement)) {
            return null;
        }

        const focusState = {
            selector: this.getElementSelector(activeElement, container),
            tagName: activeElement.tagName,
            name: activeElement.name || null,
            id: activeElement.id || null,
            selectionStart: activeElement.selectionStart || null,
            selectionEnd: activeElement.selectionEnd || null,
            scrollTop: activeElement.scrollTop || 0,
            scrollLeft: activeElement.scrollLeft || 0,
            keepFocus: activeElement.hasAttribute('data-lc-keep-focus')
        };

        this.focusStates.set(componentId, focusState);

        console.log(`[AccessibilityManager] Captured focus state for ${componentId}`, focusState);

        return focusState;
    }

    /**
     * Restore focus after update
     *
     * Restores focus to element marked with data-lc-keep-focus or previously focused element.
     *
     * @param {string} componentId - Component identifier
     * @param {HTMLElement} container - Component container element
     * @returns {boolean} True if focus was restored
     */
    restoreFocus(componentId, container) {
        const focusState = this.focusStates.get(componentId);

        if (!focusState) {
            return false;
        }

        try {
            // Find element to focus
            let elementToFocus = null;

            // Priority 1: Element with data-lc-keep-focus attribute
            if (focusState.keepFocus) {
                elementToFocus = container.querySelector('[data-lc-keep-focus]');
            }

            // Priority 2: Element matching saved selector
            if (!elementToFocus && focusState.selector) {
                elementToFocus = container.querySelector(focusState.selector);
            }

            // Priority 3: Element with same ID
            if (!elementToFocus && focusState.id) {
                elementToFocus = container.querySelector(`#${focusState.id}`);
            }

            // Priority 4: Element with same name
            if (!elementToFocus && focusState.name) {
                elementToFocus = container.querySelector(`[name="${focusState.name}"]`);
            }

            if (elementToFocus && elementToFocus.focus) {
                elementToFocus.focus();

                // Restore selection for inputs/textareas
                if (elementToFocus.setSelectionRange &&
                    focusState.selectionStart !== null &&
                    focusState.selectionEnd !== null) {
                    elementToFocus.setSelectionRange(
                        focusState.selectionStart,
                        focusState.selectionEnd
                    );
                }

                // Restore scroll position
                if (focusState.scrollTop > 0) {
                    elementToFocus.scrollTop = focusState.scrollTop;
                }
                if (focusState.scrollLeft > 0) {
                    elementToFocus.scrollLeft = focusState.scrollLeft;
                }

                console.log(`[AccessibilityManager] Restored focus to ${focusState.selector}`);

                return true;
            }

        } catch (error) {
            console.debug('[AccessibilityManager] Could not restore focus:', error);
        } finally {
            // Clean up focus state
            this.focusStates.delete(componentId);
        }

        return false;
    }

    /**
     * Get CSS selector for an element within a container
     *
     * @param {HTMLElement} element - Element to get selector for
     * @param {HTMLElement} container - Container element
     * @returns {string|null} CSS selector or null
     */
    getElementSelector(element, container) {
        // Try ID (most specific)
        if (element.id) {
            return `#${element.id}`;
        }

        // Try name attribute
        if (element.name) {
            return `[name="${element.name}"]`;
        }

        // Try data-lc-key
        const lcKey = element.getAttribute('data-lc-key');
        if (lcKey) {
            return `[data-lc-key="${lcKey}"]`;
        }

        // Try to build a path from container
        const path = [];
        let current = element;

        while (current && current !== container && current !== document.body) {
            let selector = current.tagName.toLowerCase();

            // Add class if available
            if (current.className && typeof current.className === 'string') {
                const classes = current.className.split(' ').filter(c => c.trim());
                if (classes.length > 0) {
                    selector += '.' + classes.join('.');
                }
            }

            // Add nth-child if needed for specificity
            if (current.parentElement) {
                const siblings = Array.from(current.parentElement.children);
                const index = siblings.indexOf(current) + 1;
                if (siblings.length > 1) {
                    selector += `:nth-child(${index})`;
                }
            }

            path.unshift(selector);
            current = current.parentElement;
        }

        return path.length > 0 ? path.join(' > ') : null;
    }

    /**
     * Announce component update
     *
     * Convenience method for announcing component updates.
     *
     * @param {string} componentId - Component identifier
     * @param {string} updateType - Type of update (fragment|full|action)
     * @param {Object} metadata - Additional metadata
     */
    announceUpdate(componentId, updateType, metadata = {}) {
        let message = '';

        switch (updateType) {
            case 'fragment':
                message = `Updated ${metadata.fragmentName || 'content'}`;
                break;
            case 'full':
                message = 'Component updated';
                break;
            case 'action':
                message = metadata.actionMessage || 'Action completed';
                break;
            default:
                message = 'Content updated';
        }

        this.announce(message, 'polite', componentId);
    }

    /**
     * Check if element should preserve keyboard navigation
     *
     * @param {HTMLElement} element - Element to check
     * @returns {boolean} True if keyboard navigation should be preserved
     */
    shouldPreserveKeyboardNav(element) {
        // Interactive elements that should always preserve keyboard nav
        const interactiveTags = ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON', 'A'];

        if (interactiveTags.includes(element.tagName)) {
            return true;
        }

        // Elements with tabindex
        if (element.hasAttribute('tabindex')) {
            return true;
        }

        // Elements with role
        const interactiveRoles = [
            'button', 'link', 'textbox', 'searchbox',
            'combobox', 'listbox', 'option', 'tab'
        ];

        const role = element.getAttribute('role');
        if (role && interactiveRoles.includes(role)) {
            return true;
        }

        return false;
    }

    /**
     * Cleanup component accessibility features
     *
     * @param {string} componentId - Component identifier
     */
    cleanup(componentId) {
        // Remove component live region
        const liveRegion = this.componentLiveRegions.get(componentId);
        if (liveRegion && liveRegion.parentElement) {
            liveRegion.parentElement.removeChild(liveRegion);
        }
        this.componentLiveRegions.delete(componentId);

        // Clear focus state
        this.focusStates.delete(componentId);

        console.log(`[AccessibilityManager] Cleaned up accessibility for ${componentId}`);
    }

    /**
     * Get accessibility stats
     *
     * @returns {Object} Statistics about accessibility manager state
     */
    getStats() {
        return {
            has_global_live_region: this.liveRegion !== null,
            component_live_regions: this.componentLiveRegions.size,
            tracked_focus_states: this.focusStates.size,
            pending_announcements: this.announcementQueue.length
        };
    }
}

// Create singleton instance
export const accessibilityManager = new AccessibilityManager();

export default accessibilityManager;
