import type { WindowWithLenis } from '../../animations/scrollEffects/SmoothScroll';

/**
 * BurgerMenu Component
 *
 * Handles burger menu toggle, body scroll lock, keyboard navigation, and accessibility.
 *
 * Features:
 * - Toggle menu with single burger button (transforms to cross when open)
 * - Close menu with toggle button, ESC key, or click outside (backdrop)
 * - Body scroll lock when menu is open
 * - Keyboard accessibility (Enter/Space to toggle, ESC to close, Tab navigation)
 * - ARIA attributes for screen readers
 * - Focus trap when menu is open
 */
export class BurgerMenu {
    private toggleButton: HTMLElement | null;
    private menu: HTMLElement | null;
    private backdrop: HTMLElement | null;
    private isOpen: boolean = false;
    private focusableElements: HTMLElement[] = [];
    private firstFocusableElement: HTMLElement | null = null;
    private lastFocusableElement: HTMLElement | null = null;

    constructor() {
        this.toggleButton = document.querySelector('[data-burger-toggle]');
        this.menu = document.querySelector('[data-burger-menu]');
        this.backdrop = document.querySelector('[data-burger-backdrop]');

        this.init();
    }

    private init(): void {
        if (!this.toggleButton || !this.menu || !this.backdrop) {
            return;
        }

        // Toggle button click
        this.toggleButton.addEventListener('click', () => this.toggle());

        // Backdrop click
        this.backdrop.addEventListener('click', () => this.close());

        // Keyboard events
        document.addEventListener('keydown', (e: KeyboardEvent) => this.handleKeyboard(e));

        // Toggle with Enter/Space on toggle button
        this.toggleButton.addEventListener('keydown', (e: KeyboardEvent) => {
            if (e.key === 'Enter' || e.key === ' ') {
                e.preventDefault();
                this.toggle();
            }
        });
    }

    /**
     * Toggle menu open/closed
     */
    private toggle(): void {
        if (this.isOpen) {
            this.close();
        } else {
            this.open();
        }
    }

    /**
     * Open menu
     */
    private open(): void {
        if (!this.menu || !this.toggleButton) return;

        this.isOpen = true;
        document.body.classList.add('menu-open');

        // Update ARIA attributes and label
        this.menu.setAttribute('aria-hidden', 'false');
        this.toggleButton.setAttribute('aria-expanded', 'true');
        this.toggleButton.setAttribute('aria-label', this.getCloseLabel());

        // Lock body scroll (native + Lenis, which otherwise ignores overflow:hidden)
        this.lockBodyScroll();
        (window as unknown as WindowWithLenis).lenis?.stop();

        // Setup focus trap
        this.setupFocusTrap();

        // Focus first element in menu
        setTimeout(() => {
            if (this.firstFocusableElement) {
                this.firstFocusableElement.focus();
            }
        }, 100);
    }

    /**
     * Close menu
     */
    private close(): void {
        if (!this.menu || !this.toggleButton) return;

        this.isOpen = false;
        document.body.classList.remove('menu-open');

        // Update ARIA attributes and label
        this.menu.setAttribute('aria-hidden', 'true');
        this.toggleButton.setAttribute('aria-expanded', 'false');
        this.toggleButton.setAttribute('aria-label', this.getOpenLabel());

        // Unlock body scroll (native + Lenis)
        this.unlockBodyScroll();
        (window as unknown as WindowWithLenis).lenis?.start();

        // Return focus to toggle button
        this.toggleButton.focus();
    }

    /**
     * Get localized "Open menu" label
     */
    private getOpenLabel(): string {
        const locale = document.documentElement.lang || 'fr';
        return locale === 'fr' ? 'Ouvrir le menu' : 'Open menu';
    }

    /**
     * Get localized "Close menu" label
     */
    private getCloseLabel(): string {
        const locale = document.documentElement.lang || 'fr';
        return locale === 'fr' ? 'Fermer le menu' : 'Close menu';
    }

    /**
     * Handle keyboard events
     */
    private handleKeyboard(e: KeyboardEvent): void {
        if (!this.isOpen) return;

        // ESC key closes menu
        if (e.key === 'Escape') {
            e.preventDefault();
            this.close();
            return;
        }

        // Tab key handles focus trap
        if (e.key === 'Tab') {
            this.handleTabKey(e);
        }
    }

    /**
     * Handle Tab key for focus trap
     */
    private handleTabKey(e: KeyboardEvent): void {
        if (!this.firstFocusableElement || !this.lastFocusableElement) return;

        // Shift+Tab on first element -> focus last element
        if (e.shiftKey && document.activeElement === this.firstFocusableElement) {
            e.preventDefault();
            this.lastFocusableElement.focus();
        }
        // Tab on last element -> focus first element
        else if (!e.shiftKey && document.activeElement === this.lastFocusableElement) {
            e.preventDefault();
            this.firstFocusableElement.focus();
        }
    }

    /**
     * Setup focus trap for keyboard navigation
     */
    private setupFocusTrap(): void {
        if (!this.menu) return;

        // Find all focusable elements in menu
        const focusableSelectors = [
            'a[href]',
            'button:not([disabled])',
            'input:not([disabled])',
            'select:not([disabled])',
            'textarea:not([disabled])',
            '[tabindex]:not([tabindex="-1"])'
        ];

        const elements = this.menu.querySelectorAll<HTMLElement>(focusableSelectors.join(', '));
        this.focusableElements = Array.from(elements);

        if (this.focusableElements.length > 0) {
            this.firstFocusableElement = this.focusableElements[0] ?? null;
            this.lastFocusableElement = this.focusableElements[this.focusableElements.length - 1] ?? null;
        }
    }

    /**
     * Lock body scroll when menu is open
     */
    private lockBodyScroll(): void {
        const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
        document.body.style.overflow = 'hidden';
        document.body.style.paddingRight = `${scrollbarWidth}px`;
    }

    /**
     * Unlock body scroll when menu is closed
     */
    private unlockBodyScroll(): void {
        document.body.style.overflow = '';
        document.body.style.paddingRight = '';
    }
}
