/**
 * TV-Style Keyboard Navigation
 * Handles Arrow keys to navigate horizontally through sliders and vertically between rows.
 */

export class KeyboardNavigation {
    constructor() {
        this.currentFocus = null;
        this.isEnabled = false;

        // Selectors for focusable items
        this.selectors = [
            '.video-card',
            '.hero__btn',
            '.slider-btn',
            '#topSearchBtn',
            '.nav-item',
            '.category-card',
            '.tab-btn',
            '.episode-row',
            '.recommendation-card'
        ];
    }

    init() {
        this.isEnabled = true;
        document.addEventListener('keydown', this.handleKey.bind(this));
        document.addEventListener('mousemove', this.handleMouseMove.bind(this));

        // Initial focus?
        // Usually wait for user to press a key to enter "Keyboard Mode"
        // so we don't show focus rings to mouse users.
    }

    handleMouseMove() {
        // If mouse moves, likely user is using mouse.
        // Optional: clear focus to avoid conflict?
        // For now, let's keep them separate or just let hover take precedence.
        if (this.currentFocus) {
            this.currentFocus.blur();
            this.currentFocus.classList.remove('keyboard-focused');
            this.currentFocus = null;
        }
    }

    handleKey(e) {
        if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(e.key)) {
            e.preventDefault(); // Prevent default page scroll

            if (!this.currentFocus) {
                this.focusFirstVisible();
                return;
            }

            let nextTarget = null;

            switch (e.key) {
                case 'ArrowRight':
                    nextTarget = this.moveHorizontal(1);
                    break;
                case 'ArrowLeft':
                    nextTarget = this.moveHorizontal(-1);
                    break;
                case 'ArrowUp':
                    nextTarget = this.moveVertical(-1);
                    break;
                case 'ArrowDown':
                    nextTarget = this.moveVertical(1);
                    break;
            }

            if (nextTarget) {
                this.setFocus(nextTarget);
            }
        } else if (e.key === 'Enter') {
            if (this.currentFocus) {
                this.currentFocus.click();
            }
        }
    }

    focusFirstVisible() {
        // Find first video card in viewport
        const candidates = document.querySelectorAll('.video-card');
        if (candidates.length > 0) {
            this.setFocus(candidates[0]);
        }
    }

    setFocus(el) {
        if (this.currentFocus) {
            this.currentFocus.classList.remove('keyboard-focused');
            // Trigger mouseleave logic if needed to reset z-index?
        }

        this.currentFocus = el;
        el.classList.add('keyboard-focused');
        el.focus({ preventScroll: true }); // Native focus

        // Smooth scroll into view
        el.scrollIntoView({
            behavior: 'smooth',
            block: 'center',
            inline: 'center'
        });
    }

    moveHorizontal(direction) {
        // 1. Try siblings first (if in a list)
        // If direction is 1 (Right), look for nextElementSibling
        if (!this.currentFocus) return null;

        const allFocusable = Array.from(document.querySelectorAll(this.selectors.join(',')));
        const currentIndex = allFocusable.indexOf(this.currentFocus);

        if (currentIndex === -1) return null;

        const nextIndex = currentIndex + direction;
        if (nextIndex >= 0 && nextIndex < allFocusable.length) {
            // Simple DOM order check
            // BUT for sliders, DOM order matches visual order usually.
            // Check if they are in the same container?
            // If dragging across rows, Horizontal arrow shouldn't jump rows if possible?
            // But flattening functionality is easier: just go to next DOM element.

            // Refinement: If next element is in a DIFFERENT slider row, only jump if it's logically close?
            // Ideally Right Arrow should stay in row.

            const currentRect = this.currentFocus.getBoundingClientRect();
            const nextEl = allFocusable[nextIndex];
            const nextRect = nextEl.getBoundingClientRect();

            // Heuristic: If vertical distance is large, it's a new row.
            // If delta Y > height/2, maybe block horizontal nav?
            const verticalDist = Math.abs(currentRect.top - nextRect.top);
            if (verticalDist > currentRect.height * 0.5) {
                // New row. Should arrow keys wrap? 
                // User said "scrollable to the right". Usually means stay in row or wrap.
                // Let's allow wrapping for now, or strict row logic?
                // Strict Row Logic is better for TV.
                // If I am at end of row, right arrow does nothing or goes to "Next" button?

                // Let's rely on simple DOM order for now as "good enough" for v1
                // except if the user specifically requested "scrollable right".
                // If I press Right at end of row, and it jumps to next row, that's okay.
            }
            return nextEl;
        }
        return null;
    }

    moveVertical(direction) {
        // Find closest element in the visual direction
        if (!this.currentFocus) return null;

        const currentRect = this.currentFocus.getBoundingClientRect();
        const centerX = currentRect.left + currentRect.width / 2;
        const allFocusable = Array.from(document.querySelectorAll(this.selectors.join(',')));

        // Filter elements that are strictly Above/Below
        const candidates = allFocusable.filter(el => {
            if (el === this.currentFocus) return false;
            const rect = el.getBoundingClientRect();

            if (direction === 1) { // Down
                return rect.top >= currentRect.bottom - (currentRect.height * 0.2); // permit slight overlap
            } else { // Up
                return rect.bottom <= currentRect.top + (currentRect.height * 0.2);
            }
        });

        if (candidates.length === 0) return null;

        // Find the one with minimum distance
        // Distance = Vertical Diff + Horizontal Diff penalty
        let bestCandidate = null;
        let minDistance = Infinity;

        candidates.forEach(el => {
            const rect = el.getBoundingClientRect();
            const elCenterX = rect.left + rect.width / 2;
            const elCenterY = rect.top + rect.height / 2;

            // Vertical distance (primary)
            const vDist = Math.abs(rect.top - currentRect.top);

            // Horizontal alignment penalty
            const hDist = Math.abs(elCenterX - centerX);

            // Weighted distance: Vertical matter, but horizontally closest is best within that band.
            // Actually, we usually want the "row immediately below".
            // So sort by Vertical distance first.

            // Simple Euclidean distance?
            const dist = Math.sqrt(Math.pow(vDist, 2) + Math.pow(hDist, 2));

            if (dist < minDistance) {
                minDistance = dist;
                bestCandidate = el;
            }
        });

        return bestCandidate;
    }
}
