/**
 * KV-Netflix - Main Application Entry Point
 * Initializes the video streaming application
 */

import { api } from './api.js';
import { createVideoCard } from './components/VideoCard.js';
import { initPlayer, destroyPlayer } from './components/VideoPlayer.js';
import { initSearch } from './components/SearchBar.js';
import { showToast } from './components/Toast.js';

import { createInfoModal } from './components/InfoModal.js';
import { renderNewAndHotView } from './components/NewAndHot.js';
import { KeyboardNavigation } from './keyboard-nav.js';
import { hapticLight, hapticMedium, hapticSuccess } from './haptics.js';
import { StatusBar, Style } from '../js/capacitor-mock.js';

/**
 * SplashScreen Controller
 * Manages loading progress and cinematic transition
 */
const SplashScreen = {
    elements: {
        overlay: document.getElementById('splash-screen'),
        bar: document.getElementById('loading-bar'),
        text: document.getElementById('loading-text')
    },
    progress: 0,
    isFinished: false,

    update(percent, message) {
        if (this.isFinished) return;
        this.progress = Math.min(percent, 100);
        if (this.elements.bar) this.elements.bar.style.width = `${this.progress}%`;
        if (this.elements.text && message) this.elements.text.textContent = message;

        if (this.progress >= 100) {
            this.finish();
        }
    },

    finish() {
        if (this.isFinished) return;
        this.isFinished = true;
        setTimeout(() => {
            if (this.elements.overlay) {
                this.elements.overlay.classList.add('fade-out');
                // Remove from DOM after transition to free up resources
                setTimeout(() => this.elements.overlay.remove(), 1000);
            }
        }, 500);
    }
};
// Drag scroll removed per user request
// Application state
const state = {
    videos: [],
    currentCategory: 'all',
    currentVideo: null,
    isLoading: false,
    featuredVideo: null,
    heroMovies: [],
    currentHeroIndex: 0,
    heroInterval: null,
    page: 1,
    hasMore: true
};

// DOM elements
const elements = {
    // Use videoGrid if exists, otherwise fall back to mainContent (Tailwind CSS design)
    videoGrid: document.getElementById('videoGrid') || document.getElementById('mainContent'),
    mainContent: document.getElementById('mainContent'),
    loading: document.getElementById('loading'),
    emptyState: document.getElementById('emptyState'),
    categories: document.getElementById('categories'),
    // Netflix-style navigation elements
    mainHeader: document.getElementById('mainHeader'),
    searchWrapper: document.getElementById('searchWrapper'),
    searchToggle: document.getElementById('searchToggle'),
    searchInput: document.getElementById('searchInput'),
    searchResults: document.getElementById('searchResults'),
    navLinks: document.querySelectorAll('.header__nav-link'),

    playerModal: document.getElementById('playerModal'),
    playerContainer: document.getElementById('playerContainer'),
    playerTitle: document.getElementById('playerTitle'),
    playerMeta: document.getElementById('playerMeta'),
    closePlayer: document.getElementById('closePlayer'),
    modalBackdrop: document.getElementById('modalBackdrop'),
    mobileNavItems: document.querySelectorAll('.mobile-nav__item, .sidebar__nav-item'),
    mobileBottomNavButtons: document.querySelectorAll('#mobileBottomNav .nav-item')
};

/**
 * Set the active state of mobile bottom navigation
 * @param {string} viewName - 'home', 'cinema', 'mylist', or 'search'
 */
function setMobileNavActive(viewName) {
    const navButtons = document.querySelectorAll('#mobileBottomNav .nav-item');
    navButtons.forEach(btn => {
        const isActive = btn.dataset.view === viewName;
        btn.classList.toggle('active', isActive);
        btn.classList.toggle('text-white', isActive);
        btn.classList.toggle('text-gray-400', !isActive);

        const icon = btn.querySelector('.material-symbols-outlined');
        if (icon) {
            icon.style.fontVariationSettings = isActive ? "'FILL' 1" : "'FILL' 0";
        }
    });
}


/**
 * Initialize the application
 */
async function init() {
    SplashScreen.update(10, 'Initializing services...');

    // Initialize search
    initSearch(elements.searchInput, elements.searchResults, handleVideoPlay);
    SplashScreen.update(20, 'Setting up navigation...');

    // Initialize Mobile Bottom Nav
    if (elements.mobileBottomNavButtons) {
        // ... (existing button logic)
        elements.mobileBottomNavButtons.forEach(btn => {
            btn.addEventListener('click', (e) => {
                e.preventDefault();
                const view = btn.dataset.view;
                if (!view) return;

                // Update active state
                elements.mobileBottomNavButtons.forEach(b => b.classList.remove('active'));
                btn.classList.add('active');

                // Native Haptic
                hapticLight();

                // Handle routing
                if (view === 'home') {
                    renderHome();
                    // Scroll to top for home
                    window.scrollTo({ top: 0, behavior: 'smooth' });
                } else if (view === 'search') {
                    // Mobile Search View - don't scroll to top
                    if (window.innerWidth < 768) {
                        try {
                            renderMobileSearch();
                        } catch (e) {
                            console.error('Search render failed', e);
                        }
                    } else {
                        elements.searchWrapper.classList.add('active');
                        elements.searchInput.focus();
                    }
                } else if (view === 'mylist') {
                    // My List View - don't scroll to top
                    if (window.innerWidth < 768) {
                        renderMobileMyList();
                    } else {
                        renderHistoryView('mylist');
                    }
                } else if (view === 'downloads') {
                    showToast('Downloads feature coming soon!', 'info');
                } else if (view === 'profile') {
                    renderProfileView();
                } else if (view === 'cinema') {
                    setMobileNavActive('cinema');
                    renderCategoryView('cinema');
                    // Scroll to top for category views
                    window.scrollTo({ top: 0, behavior: 'smooth' });
                } else {
                    renderCategoryView(view);
                    // Scroll to top for category views
                    window.scrollTo({ top: 0, behavior: 'smooth' });
                }
            });
        });
    }

    // Set up event listeners
    setupEventListeners();
    SplashScreen.update(40, 'Fetching movie catalog...');

    // Load home view with organized sections
    try {
        await renderCategoryView('home');
    } catch (e) {
        console.error('Home render failed', e);
    }
    SplashScreen.update(70, 'Preparing featured content...');

    // Render hero with featured content
    try {
        await renderHero();
    } catch (e) {
        console.error('Hero render failed', e);
    }
    SplashScreen.update(90, 'Applying final touches...');

    // Handle view parameter from URL (e.g. for redirects from watch page)
    const urlParams = new URLSearchParams(window.location.search);
    const viewParam = urlParams.get('view');
    if (viewParam && window.innerWidth < 768) {
        if (viewParam === 'search') renderMobileSearch();
        else if (viewParam === 'mylist') renderMobileMyList();
        else if (viewParam === 'cinema') renderCategoryView('cinema');
    }

    // Initialize TV-Style Keyboard Navigation
    const nav = new KeyboardNavigation();
    nav.init();

    // Register PWA Service Worker
    if ('serviceWorker' in navigator) {
        window.addEventListener('load', () => {
            navigator.serviceWorker.register('/sw.js')
        });
    }

    SplashScreen.update(100, 'Welcome to StreamFlix');

    // Initialize Native Status Bar
    try {
        await StatusBar.setStyle({ style: Style.Dark });
        await StatusBar.setBackgroundColor({ color: '#141414' });
    } catch (e) {
        // Fail silently
    }
}

/**
 * Render hero section with featured movie
 * @param {Object} video - Optional video object to render (defaults to state.featuredVideo)
 */
function renderHero(video = null) {
    const heroTitle = document.getElementById('heroTitle');
    const heroDescription = document.getElementById('heroDescription');
    const heroBg = document.getElementById('heroBg');
    const heroTag = document.getElementById('heroTag');
    const heroTagContainer = document.getElementById('heroTagContainer');
    const heroPlayBtn = document.getElementById('heroPlayBtn');
    const heroInfoBtn = document.getElementById('heroInfoBtn');
    const heroContent = document.getElementById('heroContent');

    // Get featured video (param, or state.featuredVideo, or first video)
    const featured = video || state.featuredVideo || state.videos[0];

    if (!featured) {
        return;
    }

    // Add fade out effect
    if (heroBg) heroBg.style.opacity = '0.5';
    if (heroContent) heroContent.style.opacity = '0';

    setTimeout(() => {
        // Update hero content
        if (heroTitle) heroTitle.textContent = featured.name || featured.title || 'Featured Movie';
        if (heroDescription) heroDescription.textContent = featured.description || featured.content || 'Watch now on StreamFlix';

        // Set background
        const backdrop = featured.backdrop || featured.poster_url || featured.thumb_url || featured.thumbnail || '';
        if (heroBg && backdrop) {
            heroBg.style.backgroundImage = `url('${backdrop}')`;
        }

        // Set category tag
        if (heroTag && heroTagContainer) {
            const genres = featured.genres || featured.category;

            // Unhide container
            heroTagContainer.classList.remove('hidden');

            if (genres && Array.isArray(genres) && genres.length > 0) {
                heroTag.textContent = genres[0];
            } else if (typeof genres === 'string') {
                heroTag.textContent = genres;
            } else {
                heroTag.textContent = '#1 in Movies Today';
            }
        }

        // Play button
        // Remove old listeners to prevent stacking
        if (heroPlayBtn && heroPlayBtn.parentNode) {
            const newPlayBtn = heroPlayBtn.cloneNode(true);
            heroPlayBtn.parentNode.replaceChild(newPlayBtn, heroPlayBtn);
            newPlayBtn.addEventListener('click', () => {
                hapticMedium();
                handleVideoPlay(featured);
            });
        }

        // Info button
        if (heroInfoBtn && heroInfoBtn.parentNode) {
            const newInfoBtn = heroInfoBtn.cloneNode(true);
            heroInfoBtn.parentNode.replaceChild(newInfoBtn, heroInfoBtn);
            newInfoBtn.addEventListener('click', () => handleShowInfo(featured));
        }

        // Fade in
        if (heroBg) heroBg.style.opacity = '1';
        if (heroContent) heroContent.style.opacity = '1';
    }, 300);

    state.featuredVideo = featured;
}

/**
 * Start Hero Carousel
 */
function startHeroCarousel() {
    if (state.heroInterval) clearInterval(state.heroInterval);

    // Only start if we have multiple movies
    if (!state.heroMovies || state.heroMovies.length <= 1) return;

    state.heroInterval = setInterval(() => {
        state.currentHeroIndex++;
        if (state.currentHeroIndex >= state.heroMovies.length) {
            state.currentHeroIndex = 0;
        }
        renderHero(state.heroMovies[state.currentHeroIndex]);
    }, 8000); // 8 seconds
}

/**
 * Stop Hero Carousel
 */
function stopHeroCarousel() {
    if (state.heroInterval) {
        clearInterval(state.heroInterval);
        state.heroInterval = null;
    }
}

/**
 * Set up event listeners
 */
function setupEventListeners() {
    // Header Scroll Effect - Master Instruction Logic
    const backToTopBtn = document.getElementById('backToTop');
    const handleScroll = () => {
        const scrollY = window.scrollY;

        // Header background change
        if (elements.mainHeader) {
            if (scrollY > 100) {
                elements.mainHeader.classList.add('scrolled');
                elements.mainHeader.style.backgroundColor = '#141414'; // Strict Netflix Black
            } else {
                elements.mainHeader.classList.remove('scrolled');
                elements.mainHeader.style.backgroundColor = 'transparent'; // Gradient handled by CSS
            }
        }

        // Back to top button visibility
        if (backToTopBtn) {
            if (scrollY > 500) {
                backToTopBtn.classList.add('visible');
            } else {
                backToTopBtn.classList.remove('visible');
            }
        }
    };
    window.addEventListener('scroll', handleScroll, { passive: true });
    // Initial check
    handleScroll();

    // Back to Top Button Click Handler
    if (backToTopBtn) {
        backToTopBtn.addEventListener('click', () => {
            window.scrollTo({
                top: 0,
                behavior: 'smooth'
            });
        });
    }

    // Expandable Search Logic - REMOVED (Unifying with Modal)

    // Category Navigation
    elements.navLinks?.forEach(link => {
        link.addEventListener('click', (e) => {
            e.preventDefault();
            const category = link.dataset.category;

            // Update active state
            elements.navLinks.forEach(l => l.classList.remove('active'));
            link.classList.add('active');

            // Load content for category
            state.currentCategory = category;
            loadVideos(category, true); // true = reset pagination
        });
    });

    // Mobile & Sidebar Navigation
    elements.mobileNavItems?.forEach(item => {
        item.addEventListener('click', (e) => {
            e.preventDefault();
            const view = item.dataset.view;

            // Update active state
            elements.mobileNavItems.forEach(i => i.classList.remove('active'));
            // If it's a sidebar item, we might need to activate all matching items (desktop + mobile logic if split)
            // For now just activate clicked
            item.classList.add('active');

            // Sync other items with same view (e.g. if both mobile nav and sidebar exist)
            elements.mobileNavItems.forEach(i => {
                if (i.dataset.view === view) i.classList.add('active');
            });

            if (view === 'home') {
                elements.videoGrid.style.display = 'block';
                const newHot = document.getElementById('newHotContainer');
                if (newHot) newHot.style.display = 'none';
                state.currentCategory = 'all';
                loadVideos('all', true);
            } else if (['movies', 'series', 'animation', 'cinema'].includes(view)) {
                // Category Views
                elements.videoGrid.style.display = 'block';
                const newHot = document.getElementById('newHotContainer');
                if (newHot) newHot.style.display = 'none';

                state.currentCategory = view;
                loadVideos(view, true); // loadVideos handles the API call with category param
            } else if (view === 'history') {
                // History & My List View (SPA)
                elements.videoGrid.style.display = 'block';
                const newHot = document.getElementById('newHotContainer');
                if (newHot) newHot.style.display = 'none';
                renderHistoryView();
            } else if (view === 'search') {
                // Trigger search modal instead of legacy view
                const searchBtn = document.getElementById('headerSearchBtn');
                if (searchBtn) searchBtn.click();
            }

            // Roll back to hero banner (scroll to top)
            window.scrollTo({ top: 0, behavior: 'smooth' });
        });
    });

    // Netflix Header Navigation (Desktop Top Nav)
    const netflixNavLinks = document.querySelectorAll('.netflix-header__nav-link');
    netflixNavLinks.forEach(link => {
        link.addEventListener('click', (e) => {
            e.preventDefault();
            const view = link.dataset.view;

            // Update active state on Netflix header
            netflixNavLinks.forEach(l => l.classList.remove('active'));
            link.classList.add('active');

            // Sync sidebar/mobile items
            elements.mobileNavItems.forEach(i => {
                i.classList.remove('active');
                if (i.dataset.view === view) i.classList.add('active');
            });

            // Handle view switching
            elements.videoGrid.style.display = 'block';
            const newHot = document.getElementById('newHotContainer');
            if (newHot) newHot.style.display = 'none';

            if (view === 'home') {
                state.currentCategory = 'all';
                loadVideos('all', true);
            } else if (['movies', 'series', 'animation', 'cinema'].includes(view)) {
                state.currentCategory = view;
                loadVideos(view, true);
            } else if (view === 'history') {
                renderHistoryView();
            }

            // Roll back to hero banner (scroll to top)
            window.scrollTo({ top: 0, behavior: 'smooth' });
        });
    });

    // Netflix Header Search Button
    const headerSearchBtn = document.getElementById('headerSearchBtn');
    if (headerSearchBtn) {
        headerSearchBtn.addEventListener('click', (e) => {
            e.preventDefault();
            const searchModal = document.getElementById('searchModal');
            const searchInput = document.getElementById('searchInput');
            if (searchModal) {
                searchModal.classList.add('active');
                if (searchInput) setTimeout(() => searchInput.focus(), 100);
            }
        });
    }

    // Mobile Search Button
    const mobileSearchBtn = document.getElementById('mobileSearchBtn');
    if (mobileSearchBtn) {
        mobileSearchBtn.addEventListener('click', (e) => {
            e.preventDefault();
            const searchModal = document.getElementById('searchModal');
            const searchInput = document.getElementById('searchInput');
            if (searchModal) {
                hapticLight();
                searchModal.classList.add('active');
                if (searchInput) setTimeout(() => searchInput.focus(), 100);
            }
        });
    }

    // Close Search Modal
    const closeSearch = document.getElementById('closeSearch');
    if (closeSearch) {
        closeSearch.addEventListener('click', () => {
            const searchModal = document.getElementById('searchModal');
            if (searchModal) searchModal.classList.remove('active');
        });
    }

    // Modal Player Back Button
    const modalPlayerBackButton = document.getElementById('modalPlayerBackButton');
    if (modalPlayerBackButton) {
        modalPlayerBackButton.addEventListener('click', () => {
            hapticLight();
            if (window.history.state?.playerOpen) {
                window.history.back();
            } else {
                closePlayerModal();
            }
        });
    }

    // Global Popstate for Modal Player
    window.addEventListener('popstate', (event) => {
        if (elements.playerModal?.classList.contains('active') && !event.state?.playerOpen) {
            closePlayerModal(false);
        }
    });

    // StreamFlix Nav Links (Tailwind design)
    const streamflixNavLinks = document.querySelectorAll('.nav-link');
    streamflixNavLinks.forEach(link => {
        link.addEventListener('click', (e) => {
            // Allow links with real href (not '#') to navigate normally
            const href = link.getAttribute('href');
            if (href && href !== '#' && !href.startsWith('#')) {
                // This is a real link (like Install App), let it navigate
                return;
            }

            e.preventDefault();
            const view = link.dataset.view;

            // Update active state
            streamflixNavLinks.forEach(l => {
                l.classList.remove('active', 'text-white');
                l.classList.add('text-gray-300');
            });
            link.classList.add('active', 'text-white');
            link.classList.remove('text-gray-300');

            // Handle view switching with organized category sections
            if (view === 'home') {
                state.currentCategory = 'all';
                renderCategoryView('home');
            } else if (view === 'series') {
                state.currentCategory = 'series';
                renderCategoryView('series');
            } else if (view === 'movies') {
                state.currentCategory = 'movies';
                renderCategoryView('movies');
            } else if (view === 'cinema') {
                state.currentCategory = 'cinema';
                renderCategoryView('cinema');
            } else if (view === 'history') {
                renderHistoryView();
            }

            // Roll back to hero banner (scroll to top)
            window.scrollTo({ top: 0, behavior: 'smooth' });
        });
    });

    // Modal close events
    elements.closePlayer?.addEventListener('click', closePlayerModal);
    elements.modalBackdrop?.addEventListener('click', closePlayerModal);


    // Keyboard shortcuts
    document.addEventListener('keydown', (e) => {
        if (e.key === 'Escape') {
            if (elements.playerModal?.classList.contains('active')) {
                if (window.history.state?.playerOpen) {
                    window.history.back();
                } else {
                    closePlayerModal();
                }
            }
            if (elements.searchWrapper?.classList.contains('active')) {
                elements.searchWrapper.classList.remove('active');
            }
            // Close search modal
            const searchModal = document.getElementById('searchModal');
            if (searchModal?.classList.contains('active')) {
                searchModal.classList.remove('active');
            }
        }
    });
}

/**
 * Load videos from API - tries RoPhim first, then database, then demo
 * @param {string} category - Optional category filter
 * @param {boolean} reset - Whether to reset pagination (e.g. category change)
 */
async function loadVideos(category = 'all', reset = false) {
    if (state.isLoading) return;
    if (reset) {
        state.page = 1;
        state.hasMore = true;
        state.videos = [];
        elements.videoGrid.innerHTML = '';
    }

    if (!state.hasMore) return;

    state.isLoading = true;
    showLoading(state.page === 1); // Only show full loader on first page

    // Helper function to add timeout to fetch
    const fetchWithTimeout = (promise, timeout = 12000) => {
        return Promise.race([
            promise,
            new Promise((_, reject) =>
                setTimeout(() => reject(new Error('Timeout')), timeout)
            )
        ]);
    };

    // Top Search Button
    const topSearchBtn = document.getElementById('topSearchBtn');
    if (topSearchBtn) {
        topSearchBtn.addEventListener('click', (e) => {
            e.preventDefault();
            const searchModal = document.getElementById('searchModal');
            const searchInput = document.getElementById('searchInput');
            if (searchModal) {
                searchModal.classList.add('active');
                if (searchInput) setTimeout(() => searchInput.focus(), 100);
            }
        });
    }

    try {

        let apiResponse = null;
        let isSectionMode = false;

        // Section Mode disabled to force Responsive Grid Layout per user request


        // Fallback: Flat Catalog
        if (!apiResponse) {
            apiResponse = await fetchWithTimeout(
                api.getRophimCatalog({
                    category: category !== 'all' ? category : null,
                    page: state.page,
                    limit: 24
                }), 12000
            );
        }



        if (apiResponse && apiResponse.movies && apiResponse.movies.length > 0) {

            // Map API data to Video objects
            const newVideos = apiResponse.movies.map(m => ({
                id: m.id || `api_${Date.now()}_${Math.random()}`,
                title: m.title || 'Unknown Title',
                thumbnail: m.thumbnail || 'https://via.placeholder.com/300x450?text=No+Image',
                backdrop: m.backdrop || m.thumbnail || 'https://via.placeholder.com/1920x1080?text=No+Backdrop',
                preview_url: m.preview_url || '',
                duration: m.duration || 0,
                resolution: m.quality || 'HD',
                category: m.category || 'movies',
                year: m.year || new Date().getFullYear(),
                description: m.description || '',
                matchScore: Math.floor(Math.random() * 15) + 85, // Random high match score
                source_url: m.source_url,
                slug: m.slug,
                // Rich Metadata
                cast: m.cast || [],
                director: m.director,
                country: m.country,
                episodes: m.episodes || []
            }));

            // Append new videos
            // Deduplicate based on ID or slug
            const existingIds = new Set(state.videos.map(v => v.id));
            const uniqueNewVideos = newVideos.filter(v => !existingIds.has(v.id));

            state.videos = [...state.videos, ...uniqueNewVideos];
            state.page += 1; // Increment page for next fetch

            // Detect if we reached end of content? (Usually API returns empty list, but here we got items)
            if (newVideos.length < 24) {
                // state.hasMore = false; // Optional optimization
            }


            // Force Responsive Grid Layout for ALL categories
            const isFirstBatch = state.page === 2; // Page bumped after fetch
            if (isFirstBatch) {
                renderVideoGrid(state.videos, false);
            } else {
                renderVideoGrid(uniqueNewVideos, true);
            }

            // Preload featured video for Hero only on first load


            // Setup/Update Infinite Scroll trigger
            setupInfiniteScrollTrigger();

            // Hide loading state on sentinel
            if (scrollSentinel) scrollSentinel.classList.remove('loading');

            state.isLoading = false;
            showLoading(false);
            return;
        } else {
            state.hasMore = false;
            // Hide sentinel when no more content
            if (scrollSentinel) {
                scrollSentinel.classList.remove('loading');
                scrollSentinel.style.display = 'none';
            }
            state.isLoading = false;
            showLoading(false);
        }

    } catch (error) {
        console.warn('API load failed:', error);
        // Only fallback to demo on first page load
        if (state.page === 1) {
            showToast('Using offline mode', 'info');
            const demoVideos = getDemoContent();
            state.videos = demoVideos;
            state.featuredVideo = demoVideos[0];
            renderVideoGrid(demoVideos);


        }
        state.isLoading = false;
        showLoading(false);
    }
}

/**
 * Render content as horizontal sliders - PhimMoi Style
 * @param {Array} videos - Videos to group
 */
/**
 * Render content as horizontal sliders - Apple TV+ Style
 * Enhanced with smart categorization and genre-based sections
 * @param {Array} videos - Videos to group
 */
/**
 * Render content as horizontal sliders - Apple TV+ Style
 * Enhanced with smart categorization and genre-based sections
 * @param {Array} videos - Videos to group
 */
function renderBackendSection(title, movies, isTop10, container = elements.videoGrid, usedIds = null) {
    if (!movies || movies.length === 0) return;

    // Deduplicate if set provided
    let uniqueMovies = movies;
    if (usedIds) {
        uniqueMovies = movies.filter(m => !usedIds.has(m.id || m.slug));
        if (uniqueMovies.length === 0) return;
        uniqueMovies.forEach(m => usedIds.add(m.id || m.slug));
    }

    // Normalize
    const normalizedVideo = uniqueMovies.map(m => ({
        id: m.id || m.slug,
        title: m.title,
        thumbnail: m.thumbnail,
        backdrop: m.backdrop || m.thumbnail,
        slug: m.slug,
        year: m.year,
        badge: m.badge,
        ranking: m.ranking
    }));

    const section = isTop10
        ? createTop10Section(title, normalizedVideo)
        : createSliderSection(title, normalizedVideo);

    container.appendChild(section);
}

async function renderSliders(videos) {
    elements.videoGrid.innerHTML = '';
    // Use Tailwind CSS layout classes
    elements.videoGrid.className = 'space-y-12';

    if (elements.emptyState) elements.emptyState.style.display = 'none';

    // 1. DISABLED: Curated sections API was overriding sectionConfigs.
    // Now using only sectionConfigs for full control over categories.
    /*
    try {
        const curatedResponse = await api.getCuratedSections();

        if (curatedResponse && curatedResponse.sections && curatedResponse.sections.length > 0) {

            curatedResponse.sections.forEach(section => {
                if (section.movies && section.movies.length > 0) {
                    // Normalize movies
                    const normalizedMovies = section.movies.map(m => ({
                        id: m.id || m.slug,
                        title: m.title,
                        thumbnail: m.thumbnail,
                        backdrop: m.poster_url || m.thumbnail,
                        slug: m.slug,
                        year: m.year,
                        quality: m.quality || 'HD',
                        resolution: m.quality || 'HD',
                        rating: m.rating,
                        tmdb_rating: m.tmdb_rating,
                        genres: m.genres,
                        category: m.category
                    }));

                    // Determine if this is a "Top Rated" section
                    const isTopRated = section.title.includes('Top Rated') || section.title.includes('🏆');

                    const sectionEl = isTopRated
                        ? createTop10Section(section.title, normalizedMovies)
                        : createSliderSection(section.title, normalizedMovies);
                    elements.videoGrid.appendChild(sectionEl);
                }
            });

            if (elements.videoGrid.children.length > 0) {
                return;
            }
        }
    } catch (e) {
        console.warn('Curated sections failed, trying backend categories...', e);
    }
    */

    // 2. DISABLED: Backend structured categories were also overriding sectionConfigs.
    // All rendering now happens in renderCategoryView() using sectionConfigs.
    /*
    try {
        let backendCategories = null;

        // Try categorySystem first, then direct API call
        if (window.categorySystem) {
            backendCategories = await window.categorySystem.loadCategories();
        }

        // Fallback: fetch directly from API
        if (!backendCategories) {
            const response = await fetch('/api/rophim/categories/all');
            const data = await response.json();
            backendCategories = data.categories;
        }

        if (backendCategories) {

            // Defined section order and titles
            const sectionConfig = [
                { key: 'hot', title: '🔥 Phim Hot (Movies)', isTop10: false },
                { key: 'top10', title: '🏆 Top 10 Phim Lẻ', isTop10: true },
                { key: 'series', title: '📺 Phim Bộ Mới (Series)', isTop10: false },
                { key: 'cinema', title: '🍿 Phim Chiếu Rạp', isTop10: false },
                { key: 'animated', title: '🎌 Hoạt Hình & Anime', isTop10: false },
                { key: 'vietnamese', title: '🇻🇳 Phim Việt Nam', isTop10: false },
                { key: 'tv_shows', title: '🎬 TV Shows', isTop10: false },
                { key: 'action', title: '💥 Action Movies', isTop10: false },
                { key: 'new_releases', title: '✨ Mới Cập Nhật', isTop10: false }
            ];

            // Track used videos to prevent duplicates across sections
            const globalUsedIds = new Set();

            // Render sections in order
            sectionConfig.forEach(config => {
                if (backendCategories[config.key] && backendCategories[config.key].length > 0) {
                    // Skip deduplication for Top 10 - it's a ranked section and should always show
                    const skipDedup = config.isTop10;
                    renderBackendSection(
                        config.title,
                        backendCategories[config.key],
                        config.isTop10,
                        elements.videoGrid,
                        skipDedup ? null : globalUsedIds
                    );
                }
            });

            // If we successfully rendered backend categories, return here
            if (elements.videoGrid.children.length > 0) {
                return;
            }
        }
    } catch (e) {
        console.warn('Failed to load backend categories, falling back to local logic', e);
    }
    */

    // --- FALLBACK / ORIGINAL LOGIC ---

    // Sort videos by year descending (newest first)
    videos.sort((a, b) => (b.year || 0) - (a.year || 0));

    // Track videos already added to sections to prevent duplicates
    const usedVideoIds = new Set();

    /**
     * Helper: Add videos to a section and track them
     */
    function addSection(title, videos, isTop10 = false) {
        if (!videos || videos.length === 0) return;

        // Filter out already-used videos
        const availableVideos = videos.filter(v => !usedVideoIds.has(v.id));
        if (availableVideos.length === 0) return;

        // Take up to 12 videos (or 10 for Top10)
        const limit = isTop10 ? 10 : 12;
        const sectionVideos = availableVideos.slice(0, limit);

        // Mark videos as used
        sectionVideos.forEach(v => usedVideoIds.add(v.id));

        // Create and append section
        const section = isTop10
            ? createTop10Section(title, sectionVideos)
            : createSliderSection(title, sectionVideos);
        elements.videoGrid.appendChild(section);

    }

    /**
     * Helper: Extract unique genres from videos
     */
    function extractGenres(videos) {
        const genreCounts = {};
        videos.forEach(v => {
            if (v.category && typeof v.category === 'string') {
                // Normalize category names
                const normalized = v.category.toLowerCase();
                const genreMap = {
                    'phim-le': 'Movies',
                    'phim-bo': 'Series',
                    'hoat-hinh': 'Animation',
                    'tv-shows': 'TV Shows'
                };
                const genre = genreMap[normalized] || v.category;
                genreCounts[genre] = (genreCounts[genre] || 0) + 1;
            }
        });
        return genreCounts;
    }

    // ==========================================
    // PRIORITY SECTION 1: Featured/Top Content
    // ==========================================
    addSection('Top Charts: Movies', videos, true);

    // ==========================================
    // PRIORITY SECTION 2: Year-Based (Newest First)
    // ==========================================
    const currentYear = new Date().getFullYear();

    addSection('2024 New Releases',
        videos.filter(v => v.year === currentYear));

    addSection('2023 Hits',
        videos.filter(v => v.year === currentYear - 1));

    // ==========================================
    // PRIORITY SECTION 3: Quality-Based
    // ==========================================
    addSection('4K Ultra HD',
        videos.filter(v => v.resolution === '4K' || v.quality === '4K'));

    // ==========================================
    // PRIORITY SECTION 4: Category-Based
    // ==========================================
    addSection('Must-Watch Series',
        videos.filter(v => v.category === 'series' || v.category === 'phim-bo' || v.category === 'tv-shows'));

    addSection('Anime & Animation',
        videos.filter(v => v.category === 'anime' || v.category === 'hoat-hinh'));

    addSection('Action & Blockbusters',
        videos.filter(v => v.category === 'movies' || v.category === 'theater' || v.category === 'phim-le'));

    // ==========================================
    // PRIORITY SECTION 5: Country/Region-Based
    // ==========================================
    addSection('Korean Cinema',
        videos.filter(v => v.country && (v.country.includes('Korea') || v.country.includes('Hàn Quốc'))));

    addSection('Japanese Films',
        videos.filter(v => v.country && (v.country.includes('Japan') || v.country.includes('Nhật Bản'))));

    addSection('Hollywood Blockbusters',
        videos.filter(v => v.country && (v.country.includes('US') || v.country.includes('USA') || v.country.includes('Mỹ'))));

    addSection('European Collection',
        videos.filter(v => v.country && (
            v.country.includes('UK') || v.country.includes('France') ||
            v.country.includes('Germany') || v.country.includes('Spain') ||
            v.country.includes('Anh') || v.country.includes('Pháp') || v.country.includes('Đức')
        )));

    addSection('Asian Cinema',
        videos.filter(v => v.country && (
            v.country.includes('China') || v.country.includes('Thailand') ||
            v.country.includes('Hong Kong') || v.country.includes('Taiwan') ||
            v.country.includes('Trung Quốc') || v.country.includes('Thái Lan') || v.country.includes('Hồng Kông')
        )));

    // ==========================================
    // PRIORITY SECTION 6: Time-Period Based
    // ==========================================
    addSection('Recent Favorites (2020-2022)',
        videos.filter(v => v.year && v.year >= 2020 && v.year <= 2022));

    addSection('Modern Classics (2015-2019)',
        videos.filter(v => v.year && v.year >= 2015 && v.year < 2020));

    addSection('Timeless Classics',
        videos.filter(v => v.year && v.year < 2015));

    // ==========================================
    // PRIORITY SECTION 7: Dynamic Genre Sections
    // ==========================================
    // Get remaining unused videos
    const unusedVideos = videos.filter(v => !usedVideoIds.has(v.id));

    if (unusedVideos.length > 0) {
        const genreCounts = extractGenres(unusedVideos);

        // Sort genres by count and create sections for top genres
        const sortedGenres = Object.entries(genreCounts)
            .sort((a, b) => b[1] - a[1])
            .slice(0, 5);

        sortedGenres.forEach(([genre, count]) => {
            if (count >= 6) {
                addSection(`${genre} Collection`,
                    unusedVideos.filter(v => v.category === genre || v.category?.toLowerCase().includes(genre.toLowerCase())));
            }
        });
    }

    // ==========================================
    // FINAL FALLBACK: Hidden Gems (minimal)
    // ==========================================
    const stillUnused = videos.filter(v => !usedVideoIds.has(v.id));

    if (stillUnused.length >= 6) {
        addSection('Hidden Gems', stillUnused);
    }

    // Log categorization summary
}

/**
 * Create a Top 10 Section with numbered rankings - PhimMoi Style
 */
function createTop10Section(title, videos) {
    const section = document.createElement('section');
    section.className = 'slider-section top10-section';

    section.innerHTML = `
        <h2 class="section-title-apple">${title}</h2>
        <div class="slider-container">
            <button class="slider-btn slider-btn--left" aria-label="Previous">
                <svg viewBox="0 0 24 24"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></svg>
            </button>
            <div class="slider-track scrollbar-hide top10-track">
                <!-- Ranked cards will be injected here -->
            </div>
            <button class="slider-btn slider-btn--right" aria-label="Next">
                <svg viewBox="0 0 24 24"><path d="M8.59 16.59L10 18l6-6-6-6-1.41 1.41L13.17 12z"/></svg>
            </button>
        </div>
    `;

    const track = section.querySelector('.slider-track');
    videos.slice(0, 10).forEach((video, index) => {
        const card = createRankedCard(video, index + 1);
        track.appendChild(card);
    });

    // Mouse drag scrolling removed per user request

    // Slider Logic
    const btnLeft = section.querySelector('.slider-btn--left');
    const btnRight = section.querySelector('.slider-btn--right');

    btnRight.addEventListener('click', () => {
        track.scrollBy({ left: window.innerWidth * 0.6, behavior: 'smooth' });
    });

    btnLeft.addEventListener('click', () => {
        track.scrollBy({ left: -window.innerWidth * 0.6, behavior: 'smooth' });
    });

    return section;
}

/**
 * Create a ranked card with number - PhimMoi Top 10 style
 */
function createRankedCard(video, rank) {
    const card = document.createElement('div');
    card.className = 'ranked-card';
    card.innerHTML = `
        <span class="rank-number">${rank}</span>
        <div class="poster-card" data-id="${video.id}">
            <img src="${video.thumbnail}" alt="${video.title}" loading="lazy">
            <span class="poster-badge">${video.resolution || 'HD'}</span>
        </div>
        <div class="ranked-info">
            <div class="ranked-title">${video.title}</div>
            <div class="ranked-meta">${video.year || ''} • ${video.country || ''}</div>
        </div>
    `;

    return card;
}

/**
 * Create a Slider Section - Netflix-style Horizontal Scroll (Tailwind CSS)
 */
/**
 * Create a Horizontal Slider Section with scroll arrows
 */
function createSliderSection(title, videos, cardType = 'poster') {
    const section = document.createElement('section');
    section.className = 'flex flex-col gap-4 mb-12 relative';

    // Section Header
    const header = document.createElement('h2');
    header.className = 'text-xl md:text-2xl font-bold text-white hover:text-primary cursor-pointer transition-colors flex items-center gap-2 group px-4 md:px-12';
    header.innerHTML = `
        ${title}
        <span class="material-symbols-outlined text-sm opacity-0 group-hover:opacity-100 transition-opacity text-primary">arrow_forward_ios</span>
    `;
    section.appendChild(header);

    // Slider wrapper (for positioning arrows)
    const sliderWrapper = document.createElement('div');
    sliderWrapper.className = 'relative group/slider';

    // Left Arrow Button
    const leftBtn = document.createElement('button');
    leftBtn.className = 'absolute left-0 top-1/2 -translate-y-1/2 z-20 w-12 h-full bg-gradient-to-r from-black/80 to-transparent opacity-0 group-hover/slider:opacity-100 transition-opacity flex items-center justify-start pl-2';
    leftBtn.innerHTML = '<span class="material-symbols-outlined text-white text-3xl">chevron_left</span>';

    // Right Arrow Button
    const rightBtn = document.createElement('button');
    rightBtn.className = 'absolute right-0 top-1/2 -translate-y-1/2 z-20 w-12 h-full bg-gradient-to-l from-black/80 to-transparent opacity-0 group-hover/slider:opacity-100 transition-opacity flex items-center justify-end pr-2';
    rightBtn.innerHTML = '<span class="material-symbols-outlined text-white text-3xl">chevron_right</span>';

    // Horizontal Scroll Container - bigger cards
    const container = document.createElement('div');
    container.className = 'flex gap-3 overflow-x-auto scroll-smooth no-scrollbar px-4 md:px-12 pb-4';

    videos.forEach((video, index) => {
        let card;
        if (cardType === 'landscape') {
            card = createContinueWatchingCard(video);
        } else {
            // All cards use horizontal orientation with larger size
            card = createTailwindCard(video, false, 0, 'horizontal');
        }
        // Apply larger fixed width for cards in slider (bigger cards)
        card.className = card.className.replace('w-full', '');
        card.style.minWidth = '280px';
        card.style.maxWidth = '380px';
        card.style.flex = '0 0 auto';
        container.appendChild(card);
    });

    // Scroll functionality
    const scrollAmount = 600;
    leftBtn.addEventListener('click', () => {
        container.scrollBy({ left: -scrollAmount, behavior: 'smooth' });
    });
    rightBtn.addEventListener('click', () => {
        container.scrollBy({ left: scrollAmount, behavior: 'smooth' });
    });

    sliderWrapper.appendChild(leftBtn);
    sliderWrapper.appendChild(container);
    sliderWrapper.appendChild(rightBtn);
    section.appendChild(sliderWrapper);

    return section;
}

/**
 * Create a movie/poster card with Tailwind CSS (Netflix style)
 */
/**
 * Create a movie/poster card with Tailwind CSS (Netflix strict style)
 */
/**
 * Create a movie/poster card with Tailwind CSS (Netflix strict style)
 */
/**
 * Create a movie/poster card with Tailwind CSS (Netflix strict style)
 * @param {Object} video - Video object
 * @param {boolean} showRank - Show ranking number
 * @param {number} rank - Rank number
 * @param {string} orientation - 'vertical' or 'horizontal'
 */
function createTailwindCard(video, showRank = false, rank = 0, orientation = 'vertical') {
    const card = document.createElement('div');

    // Let grid control width; aspect ratio for sizing
    const aspectClass = orientation === 'horizontal' ? 'aspect-video' : 'aspect-[2/3]';

    // Use w-full to fill grid cell, no fixed width
    card.className = `w-full cursor-pointer snap-start group relative transition-all duration-300 ease-in-out hover:z-30 hover:scale-105`;

    // Prioritize backdrop for horizontal cards
    let image = video.poster_url || video.thumb_url || video.thumbnail || '';
    if (orientation === 'horizontal' && video.backdrop) {
        image = video.backdrop;
    }

    // PERFORMANCE: Use image proxy with optimized sizes (quality vs speed balance)
    const isMobile = window.innerWidth < 768;
    const imageWidth = isMobile ? 180 : (orientation === 'horizontal' ? 400 : 200);
    const proxiedImage = image ? api.getProxyUrl(image, imageWidth) : '';

    const title = video.name || video.title || 'Untitled';
    const year = video.year || '';
    const quality = video.quality || 'HD';
    const slug = video.slug || video.id || '';

    // Random match score for visual fidelity (90-99%)
    const matchScore = video.matchScore || Math.floor(Math.random() * (99 - 90 + 1) + 90);

    // Simulate Rotten Tomatoes (random 80-98%)
    const rtScore = Math.floor(Math.random() * (98 - 80 + 1) + 80);

    card.innerHTML = `
        <div class="relative ${aspectClass} rounded-md overflow-hidden bg-surface-dark shadow-lg transition-all duration-300 group-hover:shadow-2xl ring-0 group-hover:ring-2 group-hover:ring-white/20">
            <div class="absolute inset-0 bg-cover bg-center transition-transform duration-500 group-hover:scale-110" style="background-image: url('${proxiedImage}');"></div>
            
            <!-- Gradient Overlay (Only visible on hover) -->
            <div class="absolute inset-0 bg-gradient-to-t from-black via-black/40 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>

            <!-- Badges Container -->
            <div class="absolute top-2 left-2 flex flex-col gap-1 z-20">
                 ${!showRank && year === new Date().getFullYear().toString() ? `<span class="bg-primary text-white text-[9px] font-bold px-1.5 py-0.5 rounded shadow">NEW</span>` : ''}
                 ${video.quality ? `<span class="bg-black/60 backdrop-blur-md text-white text-[9px] font-bold px-1.5 py-0.5 rounded border border-white/10 uppercase">${video.quality.replace('FHD', 'HD')}</span>` : ''}
                 ${video.current_episode ? `<span class="bg-black/60 backdrop-blur-md text-white text-[9px] font-bold px-1.5 py-0.5 rounded border border-white/10">EP ${video.current_episode}</span>` : ''}
            </div>

            <!-- Number Badge -->
            ${showRank ? `<span class="absolute top-0 right-0 bg-primary text-white text-4xl font-black p-2 leading-none shadow-lg z-20">${rank}</span>` : ''}
            
            <!-- Hover Content -->
            <div class="absolute inset-0 z-20 opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex flex-col justify-end p-3 pointer-events-none">
                
                <!-- Action Buttons -->
                <div class="flex items-center justify-between mb-3 pointer-events-auto">
                    <div class="flex gap-2">
                        <button class="bg-white text-black h-8 w-8 rounded-full flex items-center justify-center hover:bg-gray-200 transition-transform hover:scale-110 btn-play" title="Play">
                            <span class="material-symbols-outlined text-[20px] fill-current" style="font-variation-settings: 'FILL' 1;">play_arrow</span>
                        </button>
                        <button class="bg-zinc-800/60 backdrop-blur-md border border-gray-400 text-white h-8 w-8 rounded-full flex items-center justify-center hover:border-white hover:bg-zinc-700 transition-transform hover:scale-110 btn-add-list" data-slug="${slug}" title="Add to List">
                            <span class="material-symbols-outlined text-[18px]">add</span>
                        </button>
                    </div>
                    <button class="bg-zinc-800/60 backdrop-blur-md border border-gray-400 text-white h-8 w-8 rounded-full flex items-center justify-center hover:border-white hover:bg-zinc-700 transition-transform hover:scale-110 btn-info" data-slug="${slug}" title="More Info">
                        <span class="material-symbols-outlined text-[18px]">info</span>
                    </button>
                </div>

                <!-- Metadata -->
                <div class="space-y-1">
                     <div class="flex items-center gap-2 text-[10px] font-semibold">
                        <span class="text-green-400">${matchScore}% Match</span>
                        <span class="border border-gray-400 px-1 rounded text-gray-200">${quality}</span>
                        <span class="text-gray-300">${year}</span>
                    </div>
                    
                    <!-- Ratings & Tags -->
                    <div class="flex items-center gap-3 text-[10px] font-bold">
                        <div class="flex items-center gap-1 text-yellow-500">
                             <span class="bg-[#FA320A] text-white px-1 rounded flex items-center gap-0.5 h-3.5">
                                <span class="material-symbols-outlined text-[10px]">local_pizza</span> ${rtScore}%
                            </span>
                        </div>
                         ${video.genres && video.genres.length > 0 ? `<span class="text-white/70 font-normal truncate max-w-[100px]">${video.genres[0]}</span>` : ''}
                    </div>

                    <h3 class="text-sm font-bold text-white leading-tight line-clamp-2 drop-shadow-md mt-1">
                        ${title}
                    </h3>
                </div>
            </div>
        </div>
    `;

    // Click handler for play (background click)
    card.addEventListener('click', (e) => {
        if (!e.target.closest('button')) {
            handleVideoPlay(video);
        }
    });

    // Button Handlers
    const playBtn = card.querySelector('.btn-play');
    if (playBtn) playBtn.addEventListener('click', (e) => {
        e.stopPropagation();
        handleVideoPlay(video);
    });

    const addBtn = card.querySelector('.btn-add-list');
    if (addBtn) addBtn.addEventListener('click', (e) => {
        e.stopPropagation();
        if (window.historyService) {
            const added = window.historyService.toggleFavorite(video);
            // Visual toggle
            const icon = addBtn.querySelector('span');
            if (added) {
                icon.textContent = 'check';
                showToast('Added to My List', 'success');
            } else {
                icon.textContent = 'add';
                showToast('Removed from My List', 'info');
            }
        }
    });

    const infoBtn = card.querySelector('.btn-info');
    if (infoBtn) infoBtn.addEventListener('click', (e) => {
        e.stopPropagation();
        // Updated to use the new navigation logical as per previous request
        handleShowInfo(video);
    });

    return card;
}

/**
 * Create a Continue Watching card (landscape with progress bar)
 */
/**
 * Create a Continue Watching card (strict fit per preset)
 */
function createContinueWatchingCard(video) {
    const card = document.createElement('div');
    card.className = 'flex-none w-[280px] group/card cursor-pointer snap-start';

    const poster = video.backdrop || video.thumb_url || video.thumbnail || '';
    const title = video.name || video.title || 'Untitled';
    const progress = video.progress?.percentage || 0;
    const episode = video.progress?.episode ? `S${video.season || 1}:E${video.progress.episode}` : '';

    card.innerHTML = `
        <div class="relative aspect-video rounded-md overflow-hidden bg-surface-dark card-hover">
            <div class="absolute inset-0 bg-cover bg-center" style="background-image: url('${poster}');"></div>
            <div class="absolute inset-0 bg-black/30 group-hover/card:bg-black/10 transition-colors flex items-center justify-center opacity-0 group-hover/card:opacity-100">
                <span class="material-symbols-outlined text-5xl bg-black/50 rounded-full p-2 border-2 border-white">play_arrow</span>
            </div>
            <div class="absolute bottom-0 left-0 right-0 h-1 bg-gray-700">
                <div class="h-full bg-primary" style="width: ${progress}%;"></div>
            </div>
        </div>
        <div class="mt-2 flex justify-between items-center px-1">
            <span class="text-sm font-semibold text-gray-200">${title}</span>
            ${episode ? `<span class="text-xs text-gray-400">${episode}</span>` : ''}
        </div>
    `;

    card.addEventListener('click', () => handleVideoPlay(video));
    return card;
}




/**
 * Render video grid (standard grid for search/categories)
 * @param {Array} videos - Array of video objects
 * @param {boolean} append - Whether to append to existing grid
 */
function renderVideoGrid(videos, append = false) {
    // If not appending, clear the grid
    if (!append) {
        elements.videoGrid.innerHTML = '';
        elements.videoGrid.innerHTML = '';
        elements.videoGrid.className = 'grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-x-4 gap-y-10';
    }

    if (videos.length === 0 && !append) {
        if (elements.emptyState) elements.emptyState.style.display = 'flex';
        return;
    }

    if (elements.emptyState) elements.emptyState.style.display = 'none';

    videos.forEach(video => {
        const card = createVideoCard(video, handleVideoPlay, handleShowInfo);
        elements.videoGrid.appendChild(card);
    });
}

function renderInfiniteGrid(videos) {

    if (!videos || videos.length === 0) {
        console.warn('No videos to render in infinite grid');
        return;
    }

    let infiniteContainer = document.getElementById('infinite-scroll-container');
    if (!infiniteContainer) {
        infiniteContainer = document.createElement('div');
        infiniteContainer.id = 'infinite-scroll-container';
        // Reduce top margin as the "Khám Phá Thêm" header from renderSliders already provides spacing
        infiniteContainer.style.marginTop = '1vw';
        elements.videoGrid.appendChild(infiniteContainer);

        // Removed redundant 'More to Explore' header here as it duplicates the one from renderSliders
    }

    // Group videos by year
    const currentYear = new Date().getFullYear();
    const moviesByYear = {};

    videos.forEach(video => {
        const year = video.year || currentYear;
        if (!moviesByYear[year]) {
            moviesByYear[year] = [];
        }
        moviesByYear[year].push(video);
    });

    // Sort years descending (newest first)
    const years = Object.keys(moviesByYear).sort((a, b) => b - a);

    // Create slider sections for each year
    let cardsAdded = 0;
    years.forEach(year => {
        const movies = moviesByYear[year];
        if (movies.length > 0) {
            const yearLabel = year == currentYear ? `${year} New Releases` :
                year == currentYear - 1 ? `${year} Hits` :
                    `${year} Movies`;
            const section = createSliderSection(yearLabel, movies);
            infiniteContainer.appendChild(section);
            cardsAdded += movies.length;
        }
    });

}

let scrollObserver;
let scrollSentinel = null;
let lastScrollTrigger = 0; // Debounce timer

function setupInfiniteScrollTrigger() {
    // If no more content, hide sentinel and don't set up observer
    if (!state.hasMore) {
        if (scrollSentinel) {
            scrollSentinel.classList.remove('loading');
            scrollSentinel.style.display = 'none';
        }
        if (scrollObserver) scrollObserver.disconnect();
        return;
    }

    if (scrollObserver) scrollObserver.disconnect();

    // Remove any existing sentinels first to prevent duplicates
    document.querySelectorAll('.scroll-sentinel').forEach(el => el.remove());
    scrollSentinel = null;

    const options = {
        root: null,
        rootMargin: '50px', // Reduced from 200px to prevent early triggering
        threshold: 0.0 // Trigger when any part is visible
    };

    scrollObserver = new IntersectionObserver((entries) => {
        entries.forEach(entry => {
            // Debounce: require at least 1.5 seconds between triggers
            const now = Date.now();
            if (now - lastScrollTrigger < 1500) {
                return;
            }
            if (entry.isIntersecting && !state.isLoading && state.hasMore) {
                lastScrollTrigger = now;
                // Show loading state on sentinel
                if (scrollSentinel) scrollSentinel.classList.add('loading');
                loadVideos(state.currentCategory);
            }
        });
    }, options);

    // Create single sentinel element
    scrollSentinel = document.createElement('div');
    scrollSentinel.className = 'scroll-sentinel';
    scrollSentinel.id = 'scrollSentinel';

    // Place sentinel at the proper location - after infinite container or at end of videoGrid
    const infiniteContainer = document.getElementById('infinite-scroll-container');
    if (infiniteContainer) {
        // Insert after the infinite container for proper positioning
        infiniteContainer.parentNode.insertBefore(scrollSentinel, infiniteContainer.nextSibling);
    } else {
        elements.videoGrid.appendChild(scrollSentinel);
    }

    scrollObserver.observe(scrollSentinel);
}

function handleShowInfo(video) {
    navigateToWatch(video);
}

/**
 * Render History View - Shows user's watch history and saved content
 * @param {string} tab - 'history' or 'mylist'
 */
function renderHistoryView(tab = 'history') {
    if (elements.mainHeader) elements.mainHeader.style.display = '';
    if (!window.historyService) {
        console.error('HistoryService not initialized');
        return;
    }

    // Clear the grid
    elements.videoGrid.innerHTML = '';
    if (elements.emptyState) elements.emptyState.style.display = 'none';

    // Remove any existing history tabs
    const existingTabs = document.querySelector('.view-tabs');
    if (existingTabs) existingTabs.remove();

    // Create tabs for switching between History and My List
    const tabsContainer = document.createElement('div');
    tabsContainer.className = 'view-tabs';
    tabsContainer.innerHTML = `
        <button class="view-tab ${tab === 'history' ? 'active' : ''}" data-tab="history">Watch History</button>
        <button class="view-tab ${tab === 'mylist' ? 'active' : ''}" data-tab="mylist">My List</button>
    `;
    elements.videoGrid.before(tabsContainer);

    // Tab click listeners
    tabsContainer.querySelectorAll('.view-tab').forEach(btn => {
        btn.addEventListener('click', () => {
            tabsContainer.remove();
            renderHistoryView(btn.dataset.tab);
        });
    });

    let items = [];
    if (tab === 'history') {
        items = window.historyService.getHistory();
    } else {
        items = window.historyService.getFavorites();
    }

    if (items.length === 0) {
        if (elements.emptyState) {
            elements.emptyState.style.display = 'flex';
            const emptyTitle = elements.emptyState.querySelector('h2');
            const emptyDesc = elements.emptyState.querySelector('p');

            if (tab === 'history') {
                if (emptyTitle) emptyTitle.textContent = 'No history yet';
                if (emptyDesc) emptyDesc.textContent = 'Movies you watch will appear here.';
            } else {
                if (emptyTitle) emptyTitle.textContent = 'My List is empty';
                if (emptyDesc) emptyDesc.textContent = 'Add movies to your list to watch later.';
            }
        }
        return;
    }

    // 1. Sort by Latest (Year/Date)
    items.sort((a, b) => {
        const dateA = a.timestamp || a.year || 0;
        const dateB = b.timestamp || b.year || 0;
        return dateB - dateA;
    });

    // Normalize items with horizontal orientation for slider
    const normalizedItems = items.map((item, index) => {
        return {
            ...item,
            id: item.id || item.slug,
            orientation: 'horizontal'
        };
    });

    // Ensure header is shown
    if (elements.mainHeader) elements.mainHeader.style.display = 'block';

    // Use horizontal slider layout (same as home page)
    const title = tab === 'history' ? 'Continue Watching' : 'My List';
    const sliderSection = createSliderSection(title, normalizedItems, 'poster');
    elements.videoGrid.appendChild(sliderSection);
}

/**
 * Render Library View - Legacy fallback for history/favorites
 */
function renderLibraryView() {
    renderHistoryView('mylist');
}

/**
 * Render Movies View - Shows movies in horizontal sliders organized by year
 */
async function renderMoviesView() {
    // Show loading state
    showLoading(true);

    // Clear the grid
    elements.videoGrid.innerHTML = '';
    if (elements.emptyState) elements.emptyState.style.display = 'none';

    try {
        // Load movies if not already loaded
        if (state.videos.length === 0 || state.currentCategory !== 'movies') {
            state.currentCategory = 'movies';
            state.page = 1;
            state.hasMore = true;

            const apiResponse = await api.getRophimCatalog({
                category: 'phim-le', // movies category
                page: 1,
                limit: 48 // Load more movies for better categorization
            });

            if (apiResponse && apiResponse.movies && apiResponse.movies.length > 0) {
                state.videos = apiResponse.movies.map(m => ({
                    id: m.id || `api_${Date.now()}_${Math.random()}`,
                    title: m.title || 'Unknown Title',
                    thumbnail: m.thumbnail || 'https://via.placeholder.com/300x450?text=No+Image',
                    backdrop: m.backdrop || m.thumbnail || 'https://via.placeholder.com/1920x1080?text=No+Backdrop',
                    preview_url: m.preview_url || '',
                    duration: m.duration || 0,
                    resolution: m.quality || 'HD',
                    category: m.category || 'movies',
                    year: m.year || new Date().getFullYear(),
                    description: m.description || '',
                    matchScore: Math.floor(Math.random() * 15) + 85,
                    source_url: m.source_url,
                    slug: m.slug,
                    cast: m.cast || [],
                    director: m.director,
                    country: m.country,
                    episodes: m.episodes || []
                }));
            }
        }

        // Group movies by year
        const moviesByYear = {};
        const currentYear = new Date().getFullYear();

        state.videos.forEach(video => {
            const year = video.year || currentYear;
            if (!moviesByYear[year]) {
                moviesByYear[year] = [];
            }
            moviesByYear[year].push(video);
        });

        // Sort years descending (newest first)
        const years = Object.keys(moviesByYear).sort((a, b) => b - a);

        // Create slider sections for each year
        years.forEach(year => {
            const movies = moviesByYear[year];
            if (movies.length > 0) {
                const yearLabel = year == currentYear ? `${year} New Releases` :
                    year == currentYear - 1 ? `${year} Hits` :
                        `${year} Movies`;
                const section = createSliderSection(yearLabel, movies);
                elements.videoGrid.appendChild(section);
            }
        });

        showLoading(false);

    } catch (error) {
        console.error('Error loading movies:', error);
        showLoading(false);
        if (elements.emptyState) elements.emptyState.style.display = 'flex';
    }
}


/**
 * Render demo content when API is not available
 */
function renderDemoContent() {
    // Using CORS-friendly sample videos that work in browsers
    const SAMPLE_VIDEO = 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8'; // Big Buck Bunny HLS
    const SAMPLE_MP4 = 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4';

    const demoVideos = [
        {
            id: 1,
            title: 'Venom: The Last Dance',
            thumbnail: 'https://image.tmdb.org/t/p/w500/aosm8NMQ3UyoBVpSxyimorCQykC.jpg',
            backdrop: 'https://image.tmdb.org/t/p/original/3V4kLQg0kSqPLctI5ziYWabAZYF.jpg',
            duration: 7200,
            resolution: '4K',
            category: 'movies',
            year: 2024,
            description: 'Eddie và Venom đang chạy trốn. Bị cả hai hai thế giới truy đuổi, họ buộc phải đưa ra quyết định khốc liệt...',
        }
    ];

    // Fuzzy match title
    const isBanner = bannerCategories.some(cat => title.includes(cat));

    // Attempt to find a video with a real backdrop first (landscape)
    // to avoid stretching portrait thumbnails
    const bannerVideo = videos.find(v => v.backdrop && v.backdrop !== v.thumbnail) || videos[0] || {};
    const backdrop = bannerVideo.backdrop || bannerVideo.thumbnail || '';

    // If we are using a thumbnail (likely portrait), apply blur
    const isPortrait = backdrop === bannerVideo.thumbnail;
    const bgStyle = isPortrait ? `background-image: url('${backdrop}'); filter: blur(20px) brightness(0.7); transform: scale(1.2);` : `background-image: url('${backdrop}');`;

    if (isBanner && backdrop) {
        // Create Banner Header with separate BG for zoom effects
        const bannerHeader = document.createElement('div');
        bannerHeader.className = 'section-banner group';

        bannerHeader.innerHTML = `
            <div class="section-banner__bg" style="${bgStyle}"></div>
            <div class="section-banner__overlay"></div>
            <div class="section-banner__content">
                <h2 class="section-banner__title">${title}</h2>
                <span class="section-banner__subtitle">Explore Collection <span style="font-size: 1.2em">›</span></span>
            </div>
        `;
        section.appendChild(bannerHeader);
    } else {
        // Standard Header
        const header = document.createElement('h2');
        header.className = 'section-title-apple';
        header.textContent = title;
        section.appendChild(header);
    }

    // Split videos into chunks (Rows)
    const rowSize = 21;

    const createRow = (rowVideos) => {
        const container = document.createElement('div');
        container.className = 'slider-container';
        // Add vertical spacing between rows
        container.style.marginBottom = '1.5rem';

        container.innerHTML = `
            <button class="slider-btn slider-btn--left" aria-label="Previous">
                <svg viewBox="0 0 24 24"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></svg>
            </button>
            <div class="slider-track scrollbar-hide">
                <!-- Cards injected here -->
            </div>
            <button class="slider-btn slider-btn--right" aria-label="Next">
                <svg viewBox="0 0 24 24"><path d="M8.59 16.59L10 18l6-6-6-6-1.41 1.41L13.17 12z"/></svg>
            </button>
        `;

        const track = container.querySelector('.slider-track');
        rowVideos.forEach(video => {
            const card = createVideoCard(video, handleVideoPlay, handleShowInfo);
            track.appendChild(card);
        });

        // Slider Logic
        const btnLeft = container.querySelector('.slider-btn--left');
        const btnRight = container.querySelector('.slider-btn--right');

        btnRight.addEventListener('click', () => {
            track.scrollBy({ left: window.innerWidth * 0.7, behavior: 'smooth' });
        });

        btnLeft.addEventListener('click', () => {
            track.scrollBy({ left: -window.innerWidth * 0.7, behavior: 'smooth' });
        });

        return container;
    };

    // Create rows
    for (let i = 0; i < videos.length; i += rowSize) {
        const chunk = videos.slice(i, i + rowSize);
        // Avoid creating a tiny final row if it has very few items compared to rowSize,
        // unless it's the only row.
        if (i > 0 && chunk.length < 5) break;

        section.appendChild(createRow(chunk));
    }

    return section;
    function setupInfiniteScrollTrigger() {
        // If no more content, hide sentinel and don't set up observer
        if (!state.hasMore) {
            if (scrollSentinel) {
                scrollSentinel.classList.remove('loading');
                scrollSentinel.style.display = 'none';
            }
            if (scrollObserver) scrollObserver.disconnect();
            return;
        }

        if (scrollObserver) scrollObserver.disconnect();

        // Remove any existing sentinels first to prevent duplicates
        document.querySelectorAll('.scroll-sentinel').forEach(el => el.remove());
        scrollSentinel = null;

        const options = {
            root: null,
            rootMargin: '50px', // Reduced from 200px to prevent early triggering
            threshold: 0.0 // Trigger when any part is visible
        };

        scrollObserver = new IntersectionObserver((entries) => {
            entries.forEach(entry => {
                // Debounce: require at least 1.5 seconds between triggers
                const now = Date.now();
                if (now - lastScrollTrigger < 1500) {
                    return;
                }
                if (entry.isIntersecting && !state.isLoading && state.hasMore) {
                    lastScrollTrigger = now;
                    // Show loading state on sentinel
                    if (scrollSentinel) scrollSentinel.classList.add('loading');
                    loadVideos(state.currentCategory);
                }
            });
        }, options);

        // Create single sentinel element
        scrollSentinel = document.createElement('div');
        scrollSentinel.className = 'scroll-sentinel';
        scrollSentinel.id = 'scrollSentinel';

        // Place sentinel at the proper location - after infinite container or at end of videoGrid
        const infiniteContainer = document.getElementById('infinite-scroll-container');
        if (infiniteContainer) {
            // Insert after the infinite container for proper positioning
            infiniteContainer.parentNode.insertBefore(scrollSentinel, infiniteContainer.nextSibling);
        } else {
            elements.videoGrid.appendChild(scrollSentinel);
        }

        scrollObserver.observe(scrollSentinel);
    }

    function handleShowInfo(video) {

        // Smart Recommendations: Filter by category/genre
        let recommendations = state.videos.filter(v =>
            v.id !== video.id &&
            (v.category === video.category || v.resolution === video.resolution)
        );

        // Fallback if not enough matches
        if (recommendations.length < 6) {
            const remaining = state.videos.filter(v => v.id !== video.id && !recommendations.includes(v));
            recommendations = [...recommendations, ...remaining];
        }

        // Shuffle and slice
        recommendations = recommendations.sort(() => Math.random() - 0.5).slice(0, 6);

        const modal = createInfoModal(video, (modalEl) => {
            modalEl.classList.remove('active');
            setTimeout(() => modalEl.remove(), 400);
        }, handleVideoPlay, recommendations);

    }
}

/**
 * Render hero section with featured content
 */


/**
 * Handle video play action - Navigate to dedicated watch page
 * @param {Object} video - Video object
 */
function handleVideoPlay(video) {
    // Store video data in sessionStorage for the watch page
    sessionStorage.setItem('currentVideo', JSON.stringify(video));

    // Store all videos for recommendations
    sessionStorage.setItem('allVideos', JSON.stringify(state.videos));

    // Navigate directly to the watch page (no pushState needed for full page navigation)
    navigateToWatch(video);
}

function navigateToWatch(video) {
    window.location.href = `/watch.html?slug=${video.slug}`;
}


/**
 * Load specific episode with server
 */
async function loadEpisode(video, episode, server) {
    try {
        let streamUrl = null;
        let poster = video.thumbnail;

        // Check if this is a PhimMoiChill movie
        const isPhimMoiChill = video.source_url && (
            video.source_url.includes('royalcanalbikehire') ||
            video.source_url.includes('phimmoichill') ||
            video.source_url.includes('/phim/') ||
            video.slug
        );

        if (isPhimMoiChill) {
            showToast('Loading stream...', 'info');
            try {
                const streamData = await api.getRophimStreamByUrl(video.source_url, video.slug, episode, server);
                if (streamData && streamData.stream_url) {
                    streamUrl = streamData.stream_url;
                }
            } catch (phimmoiError) {
                console.warn('PhimMoiChill stream extraction failed:', phimmoiError.message);
            }
        }

        // Fallback: try yt-dlp extraction
        if (!streamUrl && video.source_url) {
            try {
                const extraction = await api.extractVideo(video.source_url);
                if (extraction && extraction.stream_url) {
                    streamUrl = extraction.stream_url;
                    poster = extraction.thumbnail || poster;
                }
            } catch (extractError) {
                console.warn('Extraction failed:', extractError.message);
            }
        }

        // Final fallback: use source_url directly
        if (!streamUrl && video.source_url) {
            if (video.source_url.match(/\.(mp4|m3u8|webm)(\?|$)/i)) {
                streamUrl = video.source_url;
            }
        }

        if (streamUrl) {
            const isEmbedUrl = streamUrl.includes('goatembed') ||
                streamUrl.includes('/embed/') ||
                streamUrl.includes('player.') ||
                (streamUrl.includes('embed') && !streamUrl.match(/\.(mp4|m3u8|webm)/i));

            if (isEmbedUrl) {
                elements.playerContainer.innerHTML = `
                    <div class="embed-player-wrapper" style="width: 100%; height: 100%; position: relative; background: #000;">
                        <iframe 
                            src="${streamUrl}"
                            style="width: 100%; height: 100%; border: none;"
                            allowfullscreen
                            allow="autoplay; encrypted-media; fullscreen; picture-in-picture"
                            sandbox="allow-same-origin allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox"
                        ></iframe>
                    </div>
                `;
            } else {
                const art = initPlayer(elements.playerContainer, {
                    url: streamUrl,
                    poster: poster,
                    title: video.title,
                    autoplay: true
                });

                // Push state for back navigation
                if (!window.history.state?.playerOpen) {
                    window.history.pushState({ playerOpen: true }, '', window.location.href);
                }

                if (art && window.historyService) {
                    art.on('video:timeupdate', () => {
                        const currentTime = art.currentTime;
                        const duration = art.duration;
                        if (currentTime > 0 && duration > 0 && Math.floor(currentTime) % 5 === 0) {
                            window.historyService.addToHistory(video, {
                                currentTime,
                                duration,
                                percentage: (currentTime / duration) * 100,
                                episode: 1 // Default to 1 for modal player
                            });
                        }
                    });
                }
            }
            showToast('Playing...', 'success');
        } else {
            throw new Error('Không tìm thấy nguồn phát phim');
        }

    } catch (error) {
        console.error('Video playback failed:', error);
        showToast(`Lỗi: ${error.message}`, 'error');
        elements.playerContainer.innerHTML = `
            <div class="player-skeleton" style="flex-direction: column; gap: 16px;">
                <svg viewBox="0 0 24 24" fill="currentColor" width="48" height="48" style="color: var(--color-error)">
                    <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/>
                </svg>
                <p>Cannot load video</p>
                <p style="font-size: 12px; color: var(--color-text-tertiary)">${video.title}</p>
                <button class="btn btn--ghost" onclick="location.reload()">Thử lại</button>
            </div>
        `;
    }
}


/**
 * Close player modal
 * @param {boolean} shouldUpdateHistory - Whether to update history (defaults to true)
 */
function closePlayerModal(shouldUpdateHistory = true) {
    if (elements.playerModal) {
        elements.playerModal.classList.add('hidden');
        elements.playerModal.classList.remove('active');
        elements.playerModal.style.display = 'none';

        // Destroy player
        destroyPlayer();
    }

    // If we're closing and the state still thinks it's open, and we didn't come from popstate
    if (shouldUpdateHistory && window.history.state?.playerOpen) {
        // Handled via history.back() usually
    }
    elements.playerContainer.innerHTML = '';
    state.currentVideo = null;
}
/**
 * Close add video modal
 */
function closeAddModal() {
    elements.addVideoModal.classList.remove('active');
    elements.addVideoForm.reset();
}

/**
 * Handle add video form submission
 * @param {Event} e - Form submit event
 */
async function handleAddVideo(e) {
    e.preventDefault();

    const url = document.getElementById('videoUrl').value;
    const title = document.getElementById('videoTitle').value;
    const category = document.getElementById('videoCategory').value;

    try {
        showToast('Extracting video info...', 'info');

        // First extract to get metadata
        const extraction = await api.extractVideo(url);

        // Add to library
        await api.addVideo({
            title: title || extraction.title,
            source_url: url,
            thumbnail: extraction.thumbnail,
            category: category || null
        });

        showToast('Video added successfully!', 'success');
        closeAddModal();

        // Reload videos
        await loadVideos(state.currentCategory);

    } catch (error) {
        console.error('Failed to add video:', error);
        showToast(`Failed to add video: ${error.message}`, 'error');
    }
}

/**
 * Set active category tab
 * @param {string} category - Category to activate
 */
function setActiveCategory(category) {
    state.currentCategory = category;

    elements.categories.querySelectorAll('.category').forEach(btn => {
        btn.classList.toggle('category--active', btn.dataset.category === category);
    });
}

/**
 * Show/hide loading indicator
 * @param {boolean} show - Whether to show loading
 */
function showLoading(show) {
    if (elements.loading) {
        elements.loading.style.display = show ? 'flex' : 'none';
    }
    // Support both old videoGrid and new mainContent layouts
    if (elements.videoGrid) {
        elements.videoGrid.style.display = show ? 'none' : 'block';
    }
}

/**
 * Render organized category view based on view type
 * Netflix-style: Multiple horizontal slider sections per view
 * @param {string} viewType - 'home', 'series', 'movies', or 'cinema'
 */
async function renderCategoryView(viewType) {
    // Cleanup History Tabs if they exist
    const historyTabs = document.querySelector('.view-tabs');
    if (historyTabs) historyTabs.remove();

    if (elements.mainHeader) elements.mainHeader.style.display = '';
    showLoading(true);
    elements.videoGrid.innerHTML = '';
    elements.videoGrid.className = 'space-y-12';

    // Section configurations per view type (2 rows per category)
    const sectionConfigs = {
        home: [
            { title: 'Continue Watching', type: 'history', limit: 12, cardType: 'landscape' },
            { title: 'Cinema Releases', category: 'phim-chieu-rap', limit: 12, isHeroSource: true },
            { title: 'Top Rated', category: 'phim-le', sort: 'rating', limit: 12 },
            { title: 'Action & Adventure', category: 'hanh-dong', limit: 12 },
            { title: 'Animation', category: 'hoat-hinh', limit: 12 },
            { title: 'Korean Hits', category: 'han-quoc', limit: 12 },
            { title: 'Horror & Thriller', category: 'kinh-di', limit: 12 },
            { title: 'Romance', category: 'tinh-cam', limit: 12 },
        ],
        series: [
            { title: 'Popular TV Shows', category: 'phim-bo', limit: 12, isHeroSource: true },
            { title: 'Korean Dramas', category: 'korean', limit: 12 },
            { title: 'Chinese Dramas', category: 'china', limit: 12 },
            { title: 'Anime Series', category: 'hoat-hinh', limit: 12 },
            { title: 'Documentaries', category: 'tai-lieu', limit: 12 },
        ],
        movies: [
            { title: 'Blockbuster Movies', category: 'phim-le', sort: 'year', limit: 12, isHeroSource: true },
            { title: 'Action & Adventure', category: 'action', limit: 12 },
            { title: 'Comedy Films', category: 'comedy', limit: 12 },
            { title: 'Cinema Releases', category: 'phim-chieu-rap', limit: 12 },
            { title: 'Horror Movies', category: 'kinh-di', limit: 12 },
            { title: 'Sci-Fi & Fantasy', category: 'vien-tuong', limit: 12 },
        ],
        cinema: [
            { title: 'Now Showing', category: 'phim-chieu-rap', limit: 12, isHeroSource: true },
            { title: 'New Releases', category: 'phim-le', sort: 'year', limit: 12 },
            { title: 'Top Rated', category: 'phim-le', sort: 'rating', limit: 12 },
            { title: 'Action Blockbusters', category: 'action', limit: 12 },
            { title: 'Animated Features', category: 'hoat-hinh', limit: 12 },
        ]
    };

    const sections = sectionConfigs[viewType] || sectionConfigs.home;

    // DISABLED: Session cache restoration breaks event listeners
    // Event handlers are set up via JavaScript and lost when HTML is restored
    // TODO: Implement event delegation to fix this properly
    /*
    if (viewType === 'home' || viewType === 'cinema') {
        const cachedHTML = sessionStorage.getItem(`view_cache_${viewType}`);
        if (cachedHTML) {
            elements.videoGrid.innerHTML = cachedHTML;
            showLoading(false);
            if (elements.heroContainer) elements.heroContainer.style.display = '';
            if (elements.videoGrid.children.length > 0) return;
        }
    }
    */

    // Lazy loading configuration
    const EAGER_LOAD_COUNT = 3; // Load first 3 sections immediately

    try {
        let firstAvailableMovies = null;

        // Render eager sections immediately
        for (let i = 0; i < Math.min(EAGER_LOAD_COUNT, sections.length); i++) {
            const sectionConfig = sections[i];
            const movies = await fetchSectionMovies(sectionConfig);
            if (movies && movies.length > 0) {
                if (!firstAvailableMovies) {
                    firstAvailableMovies = movies;
                }

                // Set featured video for hero banner from first valid section
                if (sectionConfig.isHeroSource && (!state.heroMovies || state.heroMovies.length === 0) && movies.length > 0) {
                    state.heroMovies = movies.slice(0, 10);
                    state.featuredVideo = movies[0];
                    state.videos = movies;
                    state.currentHeroIndex = 0;
                    renderHero(state.heroMovies[0]);
                    startHeroCarousel();
                }

                const sliderSection = createSliderSection(sectionConfig.title, movies, sectionConfig.cardType || 'poster');
                elements.videoGrid.appendChild(sliderSection);
            }
        }

        // Cache the eager sections
        if (viewType === 'home' || viewType === 'cinema') {
            sessionStorage.setItem(`view_cache_${viewType}`, elements.videoGrid.innerHTML);
        }

        // Create lazy-load placeholders for remaining sections
        const lazyObserver = new IntersectionObserver(async (entries, observer) => {
            for (const entry of entries) {
                if (entry.isIntersecting) {
                    const placeholder = entry.target;
                    const configIndex = parseInt(placeholder.dataset.configIndex);
                    const sectionConfig = sections[configIndex];

                    observer.unobserve(placeholder);

                    // Show loading indicator
                    placeholder.innerHTML = '<div class="flex justify-center py-8"><div class="loading-spinner"></div></div>';

                    const movies = await fetchSectionMovies(sectionConfig);
                    if (movies && movies.length > 0) {
                        const sliderSection = createSliderSection(sectionConfig.title, movies, sectionConfig.cardType || 'poster');
                        placeholder.replaceWith(sliderSection);

                        // Update cache as we load more
                        if (viewType === 'home' || viewType === 'cinema') {
                            sessionStorage.setItem(`view_cache_${viewType}`, elements.videoGrid.innerHTML);
                        }
                    } else {
                        placeholder.remove();
                    }
                }
            }
        }, { rootMargin: '800px' });

        // Add placeholders for lazy sections
        for (let i = EAGER_LOAD_COUNT; i < sections.length; i++) {
            const placeholder = document.createElement('div');
            placeholder.className = 'lazy-section-placeholder h-32 mb-12';
            placeholder.dataset.configIndex = i;
            placeholder.innerHTML = `<h2 class="text-xl md:text-2xl font-bold text-white/30 px-4 md:px-12">${sections[i].title}</h2>`;
            elements.videoGrid.appendChild(placeholder);
            lazyObserver.observe(placeholder);
        }

        // Fallback: If hero is still empty, use first available content

        if (!state.featuredVideo) {
            if (firstAvailableMovies && firstAvailableMovies.length > 0) {
                state.featuredVideo = firstAvailableMovies[0];
                state.videos = firstAvailableMovies;
                renderHero();
            } else {
                // Absolute final fallback: Demo content to prevent broken UI
                try {
                    const demo = getDemoContent();
                    if (demo && demo.length > 0) {
                        state.featuredVideo = demo[0];
                        state.videos = demo;
                        renderHero();
                    }
                } catch (e) { console.warn('Demo content fallback failed', e); }
            }
        }

        // If no sections were rendered, show a message
        if (elements.videoGrid.children.length === 0) {
            elements.videoGrid.innerHTML = `
                <div class="flex flex-col items-center justify-center py-20 text-gray-400">
                    <span class="material-symbols-outlined text-6xl mb-4 opacity-30">movie</span>
                    <p>No content available for this category</p>
                </div>
            `;
        }
    } catch (error) {
        console.error('Error rendering category view:', error);
        showToast('Connection failed: ' + error.message, 'error');
        elements.videoGrid.innerHTML = `
            <div class="flex flex-col items-center justify-center py-20 text-gray-400">
                <span class="material-symbols-outlined text-6xl mb-4 opacity-30">error</span>
                <p>Failed to load content. Please try again.</p>
            </div>
        `;
    }

    showLoading(false);
}

/**
 * Fetch movies for a specific section configuration
 * @param {Object} config - Section configuration
 * @returns {Array} Array of movies
 */
async function fetchSectionMovies(config) {
    try {
        // Handle history section (Continue Watching)
        if (config.type === 'history') {
            if (window.historyService) {
                const history = window.historyService.getHistory();
                return history.slice(0, config.limit).map(m => ({
                    id: m.slug || m.id,
                    title: m.title,
                    thumbnail: m.thumbnail || m.poster_url,
                    slug: m.slug,
                    year: m.year,
                    quality: m.quality || 'HD',
                    view_progress: m.view_progress || 0 // Ensure progress
                }));
            }
            return [];
        }

        // Build Base API request parameters
        const baseParams = {
            category: config.category || null,
            limit: config.limit || 40,
            sort: config.sort || 'year'
        };

        if (config.country) baseParams.country = config.country;
        if (config.genre) baseParams.genre = config.genre;

        // Strategy: Aggressive Fetching (Pages 1-8)
        // Some categories with specific sorts (like year) might have broken pagination or limited data.
        // We fetch many pages to maximize chance of filling the grid.
        const fetchPages = async (params) => {
            const promises = [1, 2, 3, 4, 5, 6, 7, 8].map(page =>
                api.getRophimCatalog({ ...params, page })
                    .catch(e => ({ movies: [] }))
            );
            const res = await Promise.all(promises);
            return res.flatMap(r => r.movies || []);
        };

        let rawMovies = await fetchPages(baseParams);

        // Fallback Strategy: If specific sort yielded too few results (< 20),
        // try fetching with default sort ('modified') to fill the grid.
        if (rawMovies.length < 20 && config.sort && config.sort !== 'modified') {
            const fallbackMovies = await fetchPages({ ...baseParams, sort: 'modified' });
            rawMovies = [...rawMovies, ...fallbackMovies];
        }

        // Deduplicate and Format
        const allMovies = [];
        const seenIds = new Set();

        for (const m of rawMovies) {
            if (!m) continue;
            const id = m.slug || m.id;
            if (!seenIds.has(id)) {
                seenIds.add(id);
                allMovies.push({
                    id: m.id || m.slug,
                    title: m.title,
                    thumbnail: m.thumbnail,
                    poster_url: m.poster_url || m.thumbnail,
                    backdrop: m.backdrop || m.poster_url || m.thumbnail,
                    slug: m.slug,
                    year: m.year,
                    quality: m.quality || 'HD',
                    rating: m.rating,
                    category: m.category
                });
            }
        }

        // Return up to limit (ensure we don't return too many if we over-fetched)
        // But also return enough to fill 6 rows if possible!
        const limit = Math.max(config.limit || 40, 48);
        return allMovies.slice(0, limit);
    } catch (error) {
        console.error(`Error fetching section "${config.title}":`, error);
        return [];
    }
}

// Initialize app when DOM is ready
if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', init);
} else {
    init();
}
/**
 * Get high-fidelity demo content for Netflix 2025 layout
 */
/**
 * Get high-fidelity demo content for Netflix 2025 layout
 */
/**
 * Get high-fidelity demo content for Netflix 2025 layout
 */
/**
 * Get high-fidelity demo content for Netflix 2025 layout
 */
function getDemoContent() {
    const SAMPLE_MP4 = 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4';

    // Unsplash Thematic Placeholders for Offline Mode
    const IMAGES = {
        VENOM: 'https://image.tmdb.org/t/p/w500/aosm8NMQ3UyoBVpSxyimorCQykC.jpg', // TMDB Verified
        SQUID: 'https://images.unsplash.com/photo-1536440136628-849c177e76a1?w=800&auto=format&fit=crop', // Red/Triangles
        ARCANE: 'https://images.unsplash.com/photo-1542751371-adc38448a05e?w=800&auto=format&fit=crop', // Neon/Cyberpunk
        PENGUIN: 'https://images.unsplash.com/photo-1478720568477-152d9b164e63?w=800&auto=format&fit=crop', // Rainy City
        GLADIATOR: 'https://images.unsplash.com/photo-1565060416-522204c35613?w=800&auto=format&fit=crop', // Colosseum
        MOANA: 'https://images.unsplash.com/photo-1507525428034-b723cf961d3e?w=800&auto=format&fit=crop', // Ocean
        WICKED: 'https://images.unsplash.com/photo-1518709268805-4e9042af9f23?w=800&auto=format&fit=crop', // Green/Magic
        DBZ: 'https://images.unsplash.com/photo-1578632767115-351597cf2477?w=800&auto=format&fit=crop' // Anime/Fire
    };

    return [
        {
            id: 'd1',
            title: 'Venom: The Last Dance',
            thumbnail: IMAGES.VENOM,
            backdrop: 'https://image.tmdb.org/t/p/original/3V4kLQg0kSqPLctI5ziYWabAZYF.jpg',
            preview_url: SAMPLE_MP4,
            duration: 7200,
            resolution: '4K',
            category: 'action',
            year: 2024,
            matchScore: 98,
            director: 'Kelly Marcel',
            country: 'USA',
            cast: ['Tom Hardy', 'Chiwetel Ejiofor', 'Juno Temple'],
            description: 'Eddie and Venom are on the run. Hunted by both of their worlds and with the net closing in, the duo are forced into a devastating decision.',
            episodes: []
        },
        {
            id: 'd2',
            title: 'Squid Game Season 2',
            thumbnail: IMAGES.SQUID,
            backdrop: IMAGES.SQUID,
            preview_url: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4',
            duration: 3600,
            resolution: 'HD',
            category: 'series',
            year: 2024,
            matchScore: 99,
            director: 'Hwang Dong-hyuk',
            country: 'Korea',
            cast: ['Lee Jung-jae', 'Lee Byung-hun', 'Wi Ha-jun'],
            description: 'Gi-hun returns to the death games after three years with a new resolution: to find the people behind and to put an end to the sport.',
            episodes: [
                { number: 1, title: 'Red Light, Green Light', url: SAMPLE_MP4 },
                { number: 2, title: 'The Man with the Umbrella', url: SAMPLE_MP4 },
                { number: 3, title: 'Stick to the Team', url: SAMPLE_MP4 }
            ]
        },
        {
            id: 'd3',
            title: 'Arcane Season 2',
            thumbnail: IMAGES.ARCANE,
            backdrop: IMAGES.ARCANE, // Use high-res version normally
            preview_url: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4',
            duration: 2400,
            resolution: '4K',
            category: 'anime',
            year: 2024,
            matchScore: 97,
            director: 'Christian Linke',
            country: 'USA, France',
            cast: ['Hailee Steinfeld', 'Ella Purnell', 'Katie Leung'],
            description: 'As conflict between Piltover and Zaun reaches a boiling point, Jinx and Vi must decide what kind of future they are fighting for.',
            episodes: [
                { number: 1, title: 'Heavy Is the Crown', url: SAMPLE_MP4 },
                { number: 2, title: 'Watch It All Burn', url: SAMPLE_MP4 },
                { number: 3, title: 'Finally Got It Right', url: SAMPLE_MP4 }
            ]
        },
        {
            id: 'd4',
            title: 'The Penguin',
            thumbnail: IMAGES.PENGUIN,
            backdrop: IMAGES.PENGUIN,
            preview_url: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerEscapes.mp4',
            duration: 3600,
            resolution: 'HD',
            category: 'series',
            year: 2024,
            matchScore: 95,
            director: 'Craig Zobel',
            country: 'USA',
            cast: ['Colin Farrell', 'Cristin Milioti', 'Rhenzy Feliz'],
            description: 'Following the events of The Batman, Oz Cobb makes a play for power in the underworld of Gotham City.',
            episodes: []
        },
        {
            id: 'd5',
            title: 'Gladiator II',
            thumbnail: IMAGES.GLADIATOR,
            backdrop: IMAGES.GLADIATOR,
            preview_url: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerFun.mp4',
            duration: 8400,
            resolution: '4K',
            category: 'action',
            year: 2024,
            matchScore: 96,
            director: 'Ridley Scott',
            country: 'USA, UK',
            cast: ['Paul Mescal', 'Pedro Pascal', 'Denzel Washington'],
            description: 'Years after witnessing the death of the revered hero Maximus at the hands of his uncle, Lucius is forced to enter the Colosseum.',
            episodes: []
        },
        {
            id: 'd6',
            title: 'Moana 2',
            thumbnail: IMAGES.MOANA,
            backdrop: IMAGES.MOANA,
            preview_url: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4',
            duration: 6000,
            resolution: 'HD',
            category: 'theater',
            year: 2024,
            matchScore: 94,
            director: 'David G. Derrick Jr.',
            country: 'USA',
            cast: ['Auliʻi Cravalho', 'Dwayne Johnson', 'Alan Tudyk'],
            description: 'After receiving an unexpected call from her wayfinding ancestors, Moana must journey to the far seas of Oceania.',
            episodes: []
        },
        {
            id: 'd7',
            title: 'Wicked',
            thumbnail: IMAGES.WICKED,
            backdrop: IMAGES.WICKED,
            preview_url: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerMeltdowns.mp4',
            duration: 9000,
            resolution: '4K',
            category: 'theater',
            year: 2024,
            matchScore: 93,
            director: 'Jon M. Chu',
            country: 'USA',
            cast: ['Cynthia Erivo', 'Ariana Grande', 'Jeff Goldblum'],
            description: 'Elphaba, a misunderstood young woman with green skin, and Glinda, a popular blonde, forge an unlikely friendship.',
            episodes: []
        },
        {
            id: 'd8',
            title: 'Dragon Ball Daima',
            thumbnail: IMAGES.DBZ,
            backdrop: IMAGES.DBZ,
            preview_url: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/Sintel.mp4',
            duration: 1440,
            resolution: 'HD',
            category: 'anime',
            year: 2024,
            matchScore: 98,
            director: 'Yoshitaka Yashima',
            country: 'Japan',
            cast: ['Masako Nozawa', 'Ryō Horikawa'],
            description: 'Goku and his friends are turned small due to a conspiracy. To fix things, they head off to a new world.',
            episodes: [
                { number: 1, title: 'Conspiracy', url: SAMPLE_MP4 }
            ]
        }
    ];
}

/**
 * Render Category Shortcuts (Horizontal Slider of Cards)
 */
function renderCategoryShortcuts() {
    const shortcuts = [
        { title: 'Phim Hot', sub: '(Movies)', tag: 'Phim Hot' },
        { title: 'Phim Bộ Mới', sub: '(Series)', tag: 'Phim Bộ Mới' },
        { title: 'Hoạt Hình & Anime', sub: '(Animation)', tag: 'Hoạt Hình' },
        { title: 'Phim Việt Nam', sub: '(Local)', tag: 'Phim Việt Nam' }
    ];

    const section = document.createElement('section');
    section.className = 'category-shortcuts-section scrollbar-hide';
    // Style handled in CSS

    const track = document.createElement('div');
    track.className = 'category-shortcuts-track';

    shortcuts.forEach(item => {
        const card = document.createElement('div');
        card.className = 'shortcut-card';
        card.innerHTML = `
            <h3>${item.title}</h3>
            <span>${item.sub}</span>
            <div class="shortcut-icon">›</div>
        `;

        card.addEventListener('click', () => {
            // Scroll to section logic
            const titles = Array.from(document.querySelectorAll('.section-title-apple, .section-banner__title'));
            const target = titles.find(t => t.textContent.includes(item.tag));
            if (target) {
                target.closest('section')?.scrollIntoView({ behavior: 'smooth', block: 'center' });
            } else {
                console.warn("Section not found:", item.tag);
            }
        });
        track.appendChild(card);
    });

    section.appendChild(track);
    return section;
}
/**
 * Render Profile View - Mobile first profile screen
 */
function renderProfileView() {
    // Show standard header and hero section
    if (elements.mainHeader) elements.mainHeader.style.display = '';
    const heroContainer = document.getElementById('heroContainer');
    if (heroContainer) {
        heroContainer.style.display = '';
        renderHero();
    }

    // Update bottom nav active state (profile is not in nav, so none will be active)
    setMobileNavActive('profile');

    // Clear content
    elements.videoGrid.innerHTML = '';
    elements.videoGrid.className = 'profile-view pb-24 bg-background-light dark:bg-background-dark min-h-screen';

    // HTML Structure based on user example
    const profileHTML = `
        <!-- Sticky Top Bar (at offset) -->
        <div class="sticky top-[60px] md:top-[80px] z-40 flex items-center bg-background-light/95 dark:bg-background-dark/95 backdrop-blur-md px-4 py-3 justify-between border-b border-gray-200 dark:border-white/10">
            <button class="flex size-10 shrink-0 items-center justify-center rounded-full hover:bg-black/5 dark:hover:bg-white/10 transition-colors" onclick="renderHome()">
                <span class="material-symbols-outlined text-slate-900 dark:text-white" style="font-size: 24px;">arrow_back</span>
            </button>
            <h2 class="text-slate-900 dark:text-white text-lg font-bold leading-tight tracking-tight flex-1 text-center">Profile</h2>
            <button class="flex w-12 items-center justify-center rounded text-sm font-semibold text-primary hover:text-red-500 transition-colors">Edit</button>
        </div>

        <div class="flex-1 overflow-y-auto no-scrollbar">
            <!-- Profile Header -->
            <div class="flex flex-col items-center pt-6 pb-6 px-4">
                <div class="relative group cursor-pointer">
                    <div class="bg-center bg-no-repeat bg-cover rounded-lg w-28 h-28 shadow-lg ring-2 ring-transparent group-hover:ring-primary transition-all duration-300" 
                         style='background-image: url("https://wallpapers.com/images/hd/netflix-profile-pictures-1000-x-1000-qo9h82134t9nv0j0.jpg");'>
                    </div>
                    <div class="absolute -bottom-2 -right-2 bg-surface-dark p-1.5 rounded-full border border-gray-700 shadow-md">
                        <span class="material-symbols-outlined text-white text-xs block">edit</span>
                    </div>
                </div>
                <h3 class="mt-4 text-2xl font-bold text-slate-900 dark:text-white tracking-tight">Isabella Hall</h3>
                <button class="mt-2 text-sm font-medium text-secondary-text hover:text-white transition-colors flex items-center gap-1">
                    Manage Profiles <span class="material-symbols-outlined text-sm">chevron_right</span>
                </button>
            </div>

            <!-- Profile Stats -->
            <div class="grid grid-cols-3 gap-3 px-4 mb-8">
                <div class="flex flex-col gap-1 rounded-lg bg-white dark:bg-[#1E1E1E] p-3 items-center text-center shadow-sm border border-gray-100 dark:border-white/5">
                    <p class="text-primary text-xl font-bold leading-tight">42</p>
                    <p class="text-slate-500 dark:text-[#B3B3B3] text-[11px] font-medium uppercase tracking-wider">Movies</p>
                </div>
                <div class="flex flex-col gap-1 rounded-lg bg-white dark:bg-[#1E1E1E] p-3 items-center text-center shadow-sm border border-gray-100 dark:border-white/5">
                    <p class="text-primary text-xl font-bold leading-tight">128h</p>
                    <p class="text-slate-500 dark:text-[#B3B3B3] text-[11px] font-medium uppercase tracking-wider">Streamed</p>
                </div>
                <div class="flex flex-col gap-1 rounded-lg bg-white dark:bg-[#1E1E1E] p-3 items-center text-center shadow-sm border border-gray-100 dark:border-white/5">
                    <p class="text-primary text-xl font-bold leading-tight">15</p>
                    <p class="text-slate-500 dark:text-[#B3B3B3] text-[11px] font-medium uppercase tracking-wider">Reviews</p>
                </div>
            </div>

            <!-- Continue Watching Container -->
            <div id="profileHistoryContainer" class="mb-8"></div>

            <!-- Menu List -->
            <div class="flex flex-col px-4 gap-2 mb-8">
                <a class="flex items-center justify-between p-4 rounded-lg bg-white dark:bg-[#1E1E1E] hover:bg-gray-50 dark:hover:bg-white/5 transition-colors group border border-gray-100 dark:border-white/5 cursor-pointer" onclick="renderHistoryView('mylist'); return false;">
                    <div class="flex items-center gap-4">
                        <div class="p-2 rounded-full bg-slate-100 dark:bg-white/10 text-slate-600 dark:text-white group-hover:text-primary transition-colors">
                            <span class="material-symbols-outlined">checklist</span>
                        </div>
                        <span class="text-base font-medium text-slate-900 dark:text-white">My List</span>
                    </div>
                    <span class="material-symbols-outlined text-secondary-text text-xl">chevron_right</span>
                </a>
                <a class="flex items-center justify-between p-4 rounded-lg bg-white dark:bg-[#1E1E1E] hover:bg-gray-50 dark:hover:bg-white/5 transition-colors group border border-gray-100 dark:border-white/5 cursor-pointer">
                    <div class="flex items-center gap-4">
                        <div class="p-2 rounded-full bg-slate-100 dark:bg-white/10 text-slate-600 dark:text-white group-hover:text-primary transition-colors">
                            <span class="material-symbols-outlined">settings</span>
                        </div>
                        <span class="text-base font-medium text-slate-900 dark:text-white">App Settings</span>
                    </div>
                    <span class="material-symbols-outlined text-secondary-text text-xl">chevron_right</span>
                </a>
                <a class="flex items-center justify-between p-4 rounded-lg bg-white dark:bg-[#1E1E1E] hover:bg-gray-50 dark:hover:bg-white/5 transition-colors group border border-gray-100 dark:border-white/5 cursor-pointer">
                    <div class="flex items-center gap-4">
                        <div class="p-2 rounded-full bg-slate-100 dark:bg-white/10 text-slate-600 dark:text-white group-hover:text-primary transition-colors">
                            <span class="material-symbols-outlined">person</span>
                        </div>
                        <span class="text-base font-medium text-slate-900 dark:text-white">Account</span>
                    </div>
                    <span class="material-symbols-outlined text-secondary-text text-xl">chevron_right</span>
                </a>
                <a class="flex items-center justify-between p-4 rounded-lg bg-white dark:bg-[#1E1E1E] hover:bg-gray-50 dark:hover:bg-white/5 transition-colors group border border-gray-100 dark:border-white/5 cursor-pointer">
                    <div class="flex items-center gap-4">
                        <div class="p-2 rounded-full bg-slate-100 dark:bg-white/10 text-slate-600 dark:text-white group-hover:text-primary transition-colors">
                            <span class="material-symbols-outlined">help</span>
                        </div>
                        <span class="text-base font-medium text-slate-900 dark:text-white">Help</span>
                    </div>
                    <span class="material-symbols-outlined text-secondary-text text-xl">chevron_right</span>
                </a>
            </div>

            <!-- Footer Actions -->
            <div class="px-4 pb-8 flex flex-col items-center gap-4">
                <button class="w-full py-3.5 px-4 rounded-lg bg-white dark:bg-transparent border border-gray-200 dark:border-gray-700 text-slate-900 dark:text-white font-semibold text-base hover:bg-gray-50 dark:hover:bg-white/5 hover:border-gray-300 dark:hover:border-gray-500 transition-all">
                    Sign Out
                </button>
                <p class="text-xs text-secondary-text">Version 4.12.0</p>
            </div>
        </div>
    `;

    elements.videoGrid.innerHTML = profileHTML;

    // Inject history
    if (window.historyService) {
        const historyItems = window.historyService.getHistory().slice(0, 10);
        if (historyItems.length > 0) {
            const historyContainer = document.getElementById('profileHistoryContainer');
            // Re-use createSliderSection. Note: it has padding baked in from previous task.
            // We might want to ensure it looks good here.
            const slider = createSliderSection('Continue Watching', historyItems, 'landscape');
            historyContainer.appendChild(slider);
        }
    }
}

/**
 * Render Home View Wrapper
 */
async function renderHome() {
    if (elements.mainHeader) elements.mainHeader.style.display = '';

    // Show hero section
    const heroContainer = document.getElementById('heroContainer');
    if (heroContainer) heroContainer.style.display = '';

    // Update bottom nav
    setMobileNavActive('home');

    // Hide footer on mobile
    if (window.innerWidth < 768) {
        document.querySelectorAll('footer').forEach(f => f.style.display = 'none');
        const searchModal = document.getElementById('searchModal');
        if (searchModal) searchModal.classList.remove('active');
    } else {
        document.querySelectorAll('footer').forEach(f => f.style.display = '');
    }

    await renderCategoryView('home');
}

/**
 * Render Mobile Search View
 */
async function renderMobileSearch() {
    // Show standard header and hero section
    if (elements.mainHeader) elements.mainHeader.style.display = '';
    const heroContainer = document.getElementById('heroContainer');
    if (heroContainer) {
        heroContainer.style.display = '';
        renderHero(); // Ensure hero is populated
    }

    // Hide all footers on mobile
    document.querySelectorAll('footer').forEach(f => f.style.display = 'none');

    // Explicitly hide search modal/popup if it somehow triggered
    const searchModal = document.getElementById('searchModal');
    if (searchModal) searchModal.classList.remove('active');

    // Update bottom nav
    setMobileNavActive('search');

    // Clear content - leave room for fixed bottom nav (80px = nav height + safe area)
    elements.videoGrid.innerHTML = '';
    elements.videoGrid.className = 'mobile-search-view bg-background-light dark:bg-background-dark';

    // HTML Structure based on user example
    const searchHTML = `
        <!-- Search Header (Sticky below main header) -->
        <div class="shrink-0 bg-background-dark/80 backdrop-blur-md pt-4 z-50 px-4 py-2 sticky top-[60px] md:top-[80px] w-full border-b border-white/5">
            <div class="flex items-center gap-3">
                <div class="relative flex-1">
                    <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none text-slate-400 dark:text-[#cc8f92]">
                        <span class="material-symbols-outlined text-[20px]">search</span>
                    </div>
                    <input autofocus class="block w-full pl-10 pr-3 py-2.5 border-none rounded-lg text-sm bg-gray-100 dark:bg-[#361618] text-slate-900 dark:text-white placeholder-slate-400 dark:placeholder-[#cc8f92]/70 focus:ring-2 focus:ring-primary focus:outline-none transition-shadow" placeholder="Search for shows, movies, genres..." type="text" id="mobileSearchInput">
                    <div class="absolute inset-y-0 right-0 pr-3 flex items-center cursor-pointer text-slate-400 dark:text-[#cc8f92]">
                        <span class="material-symbols-outlined text-[20px]">mic</span>
                    </div>
            </div>
                <button class="text-sm font-medium text-slate-500 dark:text-white/80 active:text-white" id="mobileSearchCancel">Cancel</button>
            </div>
            <!-- Filter Chips -->
            <div id="searchFilterChips" class="mt-3 flex gap-2 overflow-x-auto no-scrollbar pb-1">
                <button class="search-chip active flex h-8 shrink-0 items-center justify-center rounded-full bg-white text-black px-4" data-genre="trending">
                    <p class="text-xs font-bold leading-normal">Top Searches</p>
                </button>
                <button class="search-chip flex h-8 shrink-0 items-center justify-center rounded-full bg-gray-200 dark:bg-surface-dark border border-transparent dark:border-white/10 px-4" data-genre="hanh-dong">
                    <p class="text-slate-700 dark:text-gray-300 text-xs font-medium leading-normal">Action</p>
                </button>
                <button class="search-chip flex h-8 shrink-0 items-center justify-center rounded-full bg-gray-200 dark:bg-surface-dark border border-transparent dark:border-white/10 px-4" data-genre="hoat-hinh">
                    <p class="text-slate-700 dark:text-gray-300 text-xs font-medium leading-normal">Anime</p>
                </button>
                <button class="search-chip flex h-8 shrink-0 items-center justify-center rounded-full bg-gray-200 dark:bg-surface-dark border border-transparent dark:border-white/10 px-4" data-genre="vien-tuong">
                    <p class="text-slate-700 dark:text-gray-300 text-xs font-medium leading-normal">Sci-Fi</p>
                </button>
                <button class="search-chip flex h-8 shrink-0 items-center justify-center rounded-full bg-gray-200 dark:bg-surface-dark border border-transparent dark:border-white/10 px-4" data-genre="hai-huoc">
                    <p class="text-slate-700 dark:text-gray-300 text-xs font-medium leading-normal">Comedy</p>
                </button>
            </div>
        </div>
        
        <!-- Results/Content Area with bottom padding for nav bar -->
        <div id="mobileSearchResults" class="flex-1 overflow-y-auto no-scrollbar pt-4 pb-24">
             <div class="mb-3">
                <h2 class="text-slate-900 dark:text-white text-lg font-bold px-4">Top Searches</h2>
             </div>
             <div id="topSearchesList" class="flex flex-col gap-1"></div>
             
             <div class="pt-8 px-4">
                <h2 class="text-slate-900 dark:text-white text-lg font-bold mb-4">Recommended for You</h2>
                <div id="recommendedGrid" class="grid grid-cols-3 gap-3"></div>
             </div>
        </div>
    `;

    elements.videoGrid.innerHTML = searchHTML;

    // Wire up mobile search input with proper API search
    const mobileInput = document.getElementById('mobileSearchInput');
    const resultsContainer = document.getElementById('mobileSearchResults');
    let searchTimeout = null;

    if (mobileInput && resultsContainer) {
        mobileInput.addEventListener('input', (e) => {
            clearTimeout(searchTimeout);
            const query = e.target.value.trim();

            searchTimeout = setTimeout(async () => {
                if (query.length < 2) {
                    // Show default content (top searches, recommended)
                    return;
                }

                // Show loading
                resultsContainer.innerHTML = '<div class="flex justify-center py-12"><div class="loading-spinner"></div></div>';

                try {
                    const response = await api.searchRophim(query);

                    if (response && response.movies && response.movies.length > 0) {
                        resultsContainer.innerHTML = `
                            <h2 class="text-white text-sm font-bold px-4 mb-3">Results for "${query}"</h2>
                            <div class="grid grid-cols-3 gap-3 px-4"></div>
                        `;
                        const grid = resultsContainer.querySelector('.grid');
                        response.movies.forEach(movie => {
                            const card = document.createElement('div');
                            card.className = 'relative group aspect-[2/3] overflow-hidden rounded-lg cursor-pointer';
                            card.innerHTML = `
                                <div class="absolute inset-0 bg-cover bg-center transition-transform duration-500 group-hover:scale-110" style='background-image: url("${movie.thumbnail}");'></div>
                                <div class="absolute inset-0 bg-gradient-to-t from-black/80 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity">
                                    <div class="absolute bottom-0 left-0 right-0 p-2">
                                        <p class="text-white text-[10px] font-bold line-clamp-1">${movie.title}</p>
                                    </div>
                                </div>
                            `;
                            card.addEventListener('click', () => handleVideoPlay(movie));
                            grid.appendChild(card);
                        });
                    } else {
                        resultsContainer.innerHTML = `
                            <div class="text-center py-12">
                                <span class="material-symbols-outlined text-4xl text-white/30 mb-2">search_off</span>
                                <p class="text-white/50">No results for "${query}"</p>
                            </div>
                        `;
                    }
                } catch (error) {
                    console.error('Mobile search failed:', error);
                    resultsContainer.innerHTML = '<div class="text-center py-12 text-white/50">Search failed. Try again.</div>';
                }
            }, 300);
        });

        // Focus input automatically
        mobileInput.focus();
    }

    // Cancel button clears search and restores default content
    const cancelBtn = document.getElementById('mobileSearchCancel');
    if (cancelBtn) {
        cancelBtn.addEventListener('click', () => {
            const input = document.getElementById('mobileSearchInput');
            if (input) {
                input.value = '';
                input.focus();
            }
            // Re-render the mobile search view to restore default content
            renderMobileSearch();
        });
    }
    // Populate Top Searches (Trending)
    try {
        const trending = await api.getRophimCatalog({ category: 'trending', limit: 5 });
        if (trending && trending.movies) {
            const container = document.getElementById('topSearchesList');
            trending.movies.forEach(movie => {
                const el = document.createElement('div');
                el.className = 'group flex items-center gap-3 px-4 py-2 hover:bg-gray-100 dark:hover:bg-white/5 cursor-pointer transition-colors';
                el.innerHTML = `
                    <div class="shrink-0 relative">
                        <div class="bg-center bg-cover rounded-lg h-16 w-28 shadow-sm" style='background-image: url("${movie.thumbnail}");'></div>
                    </div>
                    <div class="flex flex-col justify-center flex-1 min-w-0">
                        <p class="text-slate-900 dark:text-white text-sm font-semibold leading-normal truncate group-hover:text-primary transition-colors">${movie.title}</p>
                        <p class="text-slate-500 dark:text-[#cc8f92] text-xs font-normal leading-normal truncate">${movie.year || '2024'}</p>
                    </div>
                    <div class="shrink-0">
                        <span class="material-symbols-outlined text-slate-400 dark:text-white text-[28px] group-hover:text-primary">play_circle</span>
                    </div>
                `;
                el.addEventListener('click', () => handleVideoPlay(movie));
                container.appendChild(el);
            });
        }

        // Populate Recommended
        const recommended = await api.getRophimCatalog({ category: 'phim-le', limit: 9 });
        if (recommended && recommended.movies) {
            const grid = document.getElementById('recommendedGrid');
            recommended.movies.forEach(movie => {
                const card = document.createElement('div');
                card.className = 'relative group aspect-[2/3] overflow-hidden rounded-lg cursor-pointer';
                card.innerHTML = `
                    <div class="absolute inset-0 bg-cover bg-center transition-transform duration-500 group-hover:scale-110" style='background-image: url("${movie.thumbnail}");'></div>
                 `;
                card.addEventListener('click', () => handleVideoPlay(movie));
                grid.appendChild(card);
            });
        }

    } catch (e) {
        console.error('Failed to load mobile search content', e);
    }

    // Set up genre filter chip click handlers
    const filterChips = document.querySelectorAll('.search-chip');
    filterChips.forEach(chip => {
        chip.addEventListener('click', async () => {
            const genre = chip.dataset.genre;
            if (!genre) return;

            // Update active chip styling
            filterChips.forEach(c => {
                c.classList.remove('active', 'bg-white', 'text-black');
                c.classList.add('bg-gray-200', 'dark:bg-surface-dark');
                const p = c.querySelector('p');
                if (p) {
                    p.classList.remove('font-bold');
                    p.classList.add('font-medium', 'text-slate-700', 'dark:text-gray-300');
                }
            });
            chip.classList.add('active', 'bg-white', 'text-black');
            chip.classList.remove('bg-gray-200', 'dark:bg-surface-dark');
            const chipP = chip.querySelector('p');
            if (chipP) {
                chipP.classList.add('font-bold');
                chipP.classList.remove('font-medium', 'text-slate-700', 'dark:text-gray-300');
            }

            // Fetch and display genre content
            const resultsContainer = document.getElementById('mobileSearchResults');
            if (resultsContainer) {
                resultsContainer.innerHTML = '<div class="flex justify-center py-12"><div class="loading-spinner"></div></div>';

                try {
                    const response = await api.getRophimCatalog({ category: genre, limit: 12 });
                    if (response && response.movies && response.movies.length > 0) {
                        const chipName = chip.querySelector('p')?.textContent || genre;
                        resultsContainer.innerHTML = `
                            <h2 class="text-white text-lg font-bold px-4 mb-4">${chipName}</h2>
                            <div class="grid grid-cols-3 gap-3 px-4"></div>
                        `;
                        const grid = resultsContainer.querySelector('.grid');
                        response.movies.forEach(movie => {
                            const card = document.createElement('div');
                            card.className = 'relative group aspect-[2/3] overflow-hidden rounded-lg cursor-pointer';
                            card.innerHTML = `
                                <div class="absolute inset-0 bg-cover bg-center transition-transform duration-500 group-hover:scale-110" style='background-image: url("${movie.thumbnail}");'></div>
                            `;
                            card.addEventListener('click', () => handleVideoPlay(movie));
                            grid.appendChild(card);
                        });
                    } else {
                        resultsContainer.innerHTML = '<p class="text-center text-gray-400 py-12">No results found</p>';
                    }
                } catch (e) {
                    console.error('Genre filter error:', e);
                    resultsContainer.innerHTML = '<p class="text-center text-gray-400 py-12">Failed to load content</p>';
                }
            }
        });
    });
}

/**
 * Render Mobile My List View - Netflix-style grid layout
 */
async function renderMobileMyList() {
    // Show standard header and hero
    if (elements.mainHeader) elements.mainHeader.style.display = '';
    const heroContainer = document.getElementById('heroContainer');
    if (heroContainer) {
        heroContainer.style.display = '';
        renderHero();
    }

    // Hide all footers on mobile
    document.querySelectorAll('footer').forEach(f => f.style.display = 'none');

    // Explicitly hide search modal/popup
    const searchModal = document.getElementById('searchModal');
    if (searchModal) searchModal.classList.remove('active');

    // Update nav active state
    setMobileNavActive('mylist');

    // Get saved items
    const items = window.historyService ? window.historyService.getFavorites() : [];

    elements.videoGrid.innerHTML = '';
    elements.videoGrid.className = 'mobile-mylist-view min-h-screen bg-background-dark pb-24';

    const mylistHTML = `
        <!-- Sticky Header (Using sticky at an offset to allow scrolling past hero and main header) -->
        <header class="sticky top-[60px] md:top-[80px] left-0 right-0 z-[100] flex flex-col bg-background-dark/90 backdrop-blur-md pt-4 border-b border-white/5">
            <div class="flex items-center justify-between px-4 pb-2">
                <h1 class="text-2xl font-bold tracking-tight text-white">My List</h1>
                <button class="flex h-10 w-10 items-center justify-center rounded-full text-white hover:bg-white/10 transition-colors">
                    <span class="material-symbols-outlined text-[24px]">edit</span>
                </button>
            </div>
            <!-- Filter Chips -->
            <div id="mylistFilterChips" class="flex w-full gap-3 overflow-x-auto px-4 pb-4 pt-2 no-scrollbar">
                <button class="mylist-chip active flex h-8 shrink-0 items-center justify-center rounded-full bg-white px-4 shadow-lg shadow-white/10" data-filter="all" data-category="trending">
                    <p class="text-xs font-bold text-black">All</p>
                </button>
                <button class="mylist-chip flex h-8 shrink-0 items-center justify-center rounded-full bg-surface-dark border border-white/20 px-4 hover:bg-white/10" data-filter="movies" data-category="phim-le">
                    <p class="text-xs font-medium text-gray-200">Movies</p>
                </button>
                <button class="mylist-chip flex h-8 shrink-0 items-center justify-center rounded-full bg-surface-dark border border-white/20 px-4 hover:bg-white/10" data-filter="tvshows" data-category="phim-bo">
                    <p class="text-xs font-medium text-gray-200">TV Shows</p>
                </button>
                <button class="mylist-chip flex h-8 shrink-0 items-center justify-center rounded-full bg-surface-dark border border-white/20 px-4 hover:bg-white/10" data-filter="anime" data-category="hoat-hinh">
                    <p class="text-xs font-medium text-gray-200">Anime</p>
                </button>
            </div>
        </header>

        <!-- Grid Container -->
        <main class="px-4 pt-4 pb-24">
            <div id="mylistGrid" class="grid grid-cols-3 gap-3"></div>
        </main>
    `;

    elements.videoGrid.innerHTML = mylistHTML;

    // Populate grid with saved items or fallback content
    const grid = document.getElementById('mylistGrid');

    if (items.length > 0) {
        items.forEach(movie => {
            const card = document.createElement('div');
            card.className = 'group relative flex flex-col gap-2 cursor-pointer';
            card.innerHTML = `
                <div class="relative w-full overflow-hidden rounded-md bg-surface-dark shadow-md aspect-[2/3]">
                    <div class="absolute inset-0 bg-cover bg-center transition-transform duration-500 group-hover:scale-105" 
                         style='background-image: url("${movie.thumbnail || movie.poster_url}");'></div>
                    <div class="absolute inset-0 bg-black/0 transition-colors group-active:bg-black/20"></div>
                </div>
            `;
            card.addEventListener('click', () => handleVideoPlay(movie));
            grid.appendChild(card);
        });
    } else {
        // Load trending as placeholder
        try {
            const trending = await api.getRophimCatalog({ category: 'trending', limit: 12 });
            if (trending && trending.movies) {
                trending.movies.forEach((movie, index) => {
                    const card = document.createElement('div');
                    card.className = 'group relative flex flex-col gap-2 cursor-pointer';
                    card.innerHTML = `
                        <div class="relative w-full overflow-hidden rounded-md bg-surface-dark shadow-md aspect-[2/3]">
                            <div class="absolute inset-0 bg-cover bg-center transition-transform duration-500 group-hover:scale-105" 
                                 style='background-image: url("${movie.thumbnail}");'></div>
                            ${index === 0 ? '<div class="absolute top-0 right-0 rounded-bl-md bg-primary px-1.5 py-0.5"><span class="text-[10px] font-bold uppercase text-white tracking-wider">New</span></div>' : ''}
                            <div class="absolute inset-0 bg-black/0 transition-colors group-active:bg-black/20"></div>
                        </div>
                    `;
                    card.addEventListener('click', () => handleVideoPlay(movie));
                    grid.appendChild(card);
                });
            }
        } catch (e) {
            console.error('Failed to load my list content', e);
        }
    }

    // Set up My List filter chip click handlers
    const mylistChips = document.querySelectorAll('.mylist-chip');
    mylistChips.forEach(chip => {
        chip.addEventListener('click', async () => {
            const filter = chip.dataset.filter;
            const category = chip.dataset.category;
            if (!filter || !category) return;

            // Update active chip styling
            mylistChips.forEach(c => {
                c.classList.remove('active', 'bg-white');
                c.classList.add('bg-surface-dark');
                const p = c.querySelector('p');
                if (p) {
                    p.classList.remove('font-bold', 'text-black');
                    p.classList.add('font-medium', 'text-gray-200');
                }
            });
            chip.classList.add('active', 'bg-white');
            chip.classList.remove('bg-surface-dark');
            const chipP = chip.querySelector('p');
            if (chipP) {
                chipP.classList.add('font-bold', 'text-black');
                chipP.classList.remove('font-medium', 'text-gray-200');
            }

            // Fetch and display filtered content
            const grid = document.getElementById('mylistGrid');
            if (grid) {
                grid.innerHTML = '<div class="col-span-3 flex justify-center py-12"><div class="loading-spinner"></div></div>';

                try {
                    const response = await api.getRophimCatalog({ category: category, limit: 12 });
                    grid.innerHTML = '';
                    if (response && response.movies && response.movies.length > 0) {
                        response.movies.forEach((movie, index) => {
                            const card = document.createElement('div');
                            card.className = 'group relative flex flex-col gap-2 cursor-pointer';
                            card.innerHTML = `
                                <div class="relative w-full overflow-hidden rounded-md bg-surface-dark shadow-md aspect-[2/3]">
                                    <div class="absolute inset-0 bg-cover bg-center transition-transform duration-500 group-hover:scale-105" 
                                         style='background-image: url("${movie.thumbnail}");'></div>
                                    ${index === 0 ? '<div class="absolute top-0 right-0 rounded-bl-md bg-primary px-1.5 py-0.5"><span class="text-[10px] font-bold uppercase text-white tracking-wider">New</span></div>' : ''}
                                    <div class="absolute inset-0 bg-black/0 transition-colors group-active:bg-black/20"></div>
                                </div>
                            `;
                            card.addEventListener('click', () => handleVideoPlay(movie));
                            grid.appendChild(card);
                        });
                    } else {
                        grid.innerHTML = '<p class="col-span-3 text-center text-gray-400 py-12">No content found</p>';
                    }
                } catch (e) {
                    console.error('Filter error:', e);
                    grid.innerHTML = '<p class="col-span-3 text-center text-gray-400 py-12">Failed to load content</p>';
                }
            }
        });
    });
}
