// ============================================================
// Media Browser: Navigation, rendering, search, pagination
// ============================================================

import {
    t, showToast, showConfirm, escapeHtml, closeDialog,
    SEARCH_DEBOUNCE_MS, EMPTY_SVG_FILE, EMPTY_SVG_FOLDER, emptyStateHtml,
    getAuthHeaders, hasCredentials,
} from './core.js';

// Browser state
let currentFolderId = null;
let currentPath = '';
let currentOffset = 0;
let itemsPerPage = parseInt(localStorage.getItem('mediaBrowser.itemsPerPage')) || 100;
let totalItems = 0;
let mediaFolders = {};
let managementEnabled = false;
let viewMode = localStorage.getItem('mediaBrowser.viewMode') || 'grid';
let cachedItems = null;
let browserSearchTerm = '';
let browserSearchTimer = null;
export const thumbnailCache = new Map();
const THUMBNAIL_CACHE_MAX = 200;

// Load media folders on page load
export async function loadMediaFolders() {
    try {
        if (!hasCredentials()) return;

        const response = await fetch('/api/browser/folders', {
            headers: getAuthHeaders()
        });

        if (!response.ok) throw new Error('Failed to load folders');

        const data = await response.json();
        mediaFolders = data.folders || {};
        managementEnabled = data.management_enabled || false;

        // Show/hide the media folders settings section
        const section = document.getElementById('mediaFoldersSection');
        if (section) {
            section.style.display = managementEnabled ? '' : 'none';
        }

        // Render folders table in settings if management is enabled
        if (managementEnabled) {
            loadFoldersTable();
        }

        // Load last browsed path or show root folder list
        loadLastBrowserPath();
    } catch (error) {
        console.error('Error loading media folders:', error);
        showToast(t('browser.error_loading_folders'), 'error');
    }
}

function showRootFolders() {
    currentFolderId = '';
    currentPath = '';
    currentOffset = 0;
    cachedItems = null;

    // Hide search at root level
    showBrowserSearch(false);

    // Render breadcrumb with just "Home" (already at root — not interactive).
    const breadcrumb = document.getElementById('breadcrumb');
    breadcrumb.innerHTML = '';
    const root = document.createElement('span');
    root.className = 'breadcrumb-item breadcrumb-home';
    root.setAttribute('aria-current', 'page');
    root.setAttribute('aria-label', t('browser.home') || 'Home');
    root.innerHTML = '<svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true"><path fill="currentColor" d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/></svg>';
    breadcrumb.appendChild(root);

    // Hide play all button and pagination
    document.getElementById('playAllBtn').style.display = 'none';
    document.getElementById('browserPagination').style.display = 'none';

    // Render folders as grid cards
    const container = document.getElementById('browserGrid');
    revokeBlobUrls(container);
    if (viewMode === 'list') {
        container.className = 'browser-list';
    } else {
        container.className = 'browser-grid browser-root-grid';
    }
    container.innerHTML = '';

    const folderSvg = '<svg viewBox="0 0 24 24" width="24" height="24"><path fill="currentColor" d="M10 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/></svg>';

    Object.entries(mediaFolders).forEach(([id, folder]) => {
        if (!folder.enabled) return;
        const unavailable = folder.available === false;
        const unavailableClass = unavailable ? ' unavailable' : '';

        if (viewMode === 'list') {
            const row = document.createElement('div');
            row.className = 'browser-list-item' + unavailableClass;
            if (!unavailable) {
                row.onclick = () => {
                    currentFolderId = id;
                    browsePath(id, '');
                };
            }
            row.innerHTML = `
                <div class="browser-list-icon" style="color: var(--accent)">${folderSvg}</div>
                <div class="browser-list-name">${escapeHtml(folder.label)}${unavailable ? ' <span class="folder-unavailable-badge">' + t('browser.unavailable') + '</span>' : ''}</div>
            `;
            container.appendChild(row);
        } else {
            const card = document.createElement('div');
            card.className = 'browser-item browser-root-folder' + unavailableClass;
            if (!unavailable) {
                card.onclick = () => {
                    currentFolderId = id;
                    browsePath(id, '');
                };
            }
            card.innerHTML = `
                <div class="browser-thumb-wrapper">
                    <div class="browser-icon" style="color: var(--accent)">${folderSvg}</div>
                </div>
                <div class="browser-item-info">
                    <div class="browser-item-name">${escapeHtml(folder.label)}</div>
                    ${unavailable ? '<div class="browser-item-meta folder-unavailable-badge">' + t('browser.unavailable') + '</div>' : ''}
                </div>
            `;
            container.appendChild(card);
        }
    });
}

async function browsePath(folderId, path, offset = 0, nocache = false) {
    // Clear search when navigating; bump browse generation so in-flight
    // thumbnail fetches from the previous folder can be discarded.
    showBrowserSearch(false);
    bumpBrowseGen();

    try {
        if (!hasCredentials()) return;

        // Show loading spinner
        const container = document.getElementById('browserGrid');
        container.className = 'browser-grid';
        container.innerHTML = '<div class="browser-loading"><div class="loading-spinner"></div></div>';

        const encodedPath = encodeURIComponent(path);
        let url = `/api/browser/browse?folder_id=${folderId}&path=${encodedPath}&offset=${offset}&limit=${itemsPerPage}`;
        if (nocache) url += '&nocache=true';
        const response = await fetch(
            url,
            { headers: getAuthHeaders() }
        );

        if (!response.ok) {
            let errorMsg = 'Failed to browse path';
            if (response.status === 503) {
                const errorData = await response.json().catch(() => ({}));
                errorMsg = errorData.detail || 'Folder is temporarily unavailable (network share not accessible)';
            }
            throw new Error(errorMsg);
        }

        const data = await response.json();
        currentPath = data.current_path;
        currentOffset = offset;
        totalItems = data.total;

        cachedItems = data.items;
        renderBreadcrumbs(data.current_path, data.parent_path);
        renderBrowserItems(cachedItems);
        renderPagination();

        // Show search bar when inside a folder
        showBrowserSearch(true);

        // Show/hide Play All button based on whether media items exist
        const hasMedia = data.items.some(item => item.is_media);
        document.getElementById('playAllBtn').style.display = hasMedia ? '' : 'none';

        // Save last path
        saveLastBrowserPath(folderId, currentPath);
    } catch (error) {
        console.error('Error browsing path:', error);
        const errorMsg = error.message || t('browser.error_loading');
        showToast(errorMsg, 'error');
        clearBrowserGrid();
    }
}

function renderBreadcrumbs(currentPathStr, parentPath) {
    const breadcrumb = document.getElementById('breadcrumb');
    breadcrumb.innerHTML = '';

    const parts = (currentPathStr || '').split('/').filter(p => p);
    let path = '/';

    // Home link (back to folder list) — use a real <button> so it's
    // keyboard-focusable and reachable by screen readers.
    const home = document.createElement('button');
    home.type = 'button';
    home.className = 'breadcrumb-item breadcrumb-home';
    home.setAttribute('aria-label', t('browser.home') || 'Home');
    home.innerHTML = '<svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true"><path fill="currentColor" d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/></svg>';
    home.onclick = () => showRootFolders();
    breadcrumb.appendChild(home);

    // Separator + Folder name
    const sep = document.createElement('span');
    sep.className = 'breadcrumb-separator';
    sep.textContent = '\u203A';
    breadcrumb.appendChild(sep);

    const folderItem = document.createElement('span');
    folderItem.className = 'breadcrumb-item';
    folderItem.textContent = mediaFolders[currentFolderId]?.label || 'Root';
    if (parts.length > 0) {
        folderItem.onclick = () => browsePath(currentFolderId, '');
    }
    breadcrumb.appendChild(folderItem);

    // Path parts
    parts.forEach((part, index) => {
        // Separator
        const separator = document.createElement('span');
        separator.className = 'breadcrumb-separator';
        separator.textContent = '\u203A';
        breadcrumb.appendChild(separator);

        // Part
        path += (path === '/' ? '' : '/') + part;
        const item = document.createElement('span');
        item.className = 'breadcrumb-item';
        item.textContent = part;
        const itemPath = path;
        item.onclick = () => browsePath(currentFolderId, itemPath);
        breadcrumb.appendChild(item);
    });
}

function revokeBlobUrls(container) {
    const cachedUrls = new Set(thumbnailCache.values());
    container.querySelectorAll('img[src^="blob:"]').forEach(img => {
        // Don't revoke URLs managed by the thumbnail cache
        if (!cachedUrls.has(img.src)) {
            URL.revokeObjectURL(img.src);
        }
    });
}

function renderBrowserItems(items) {
    const container = document.getElementById('browserGrid');
    revokeBlobUrls(container);
    // Switch container class based on view mode
    if (viewMode === 'list') {
        container.className = 'browser-list';
        renderBrowserList(items, container);
    } else if (viewMode === 'compact') {
        container.className = 'browser-grid browser-grid-compact';
        renderBrowserGrid(items, container);
    } else {
        container.className = 'browser-grid';
        renderBrowserGrid(items, container);
    }
}

function renderBrowserList(items, container) {
    container.innerHTML = '';

    if (!items || items.length === 0) {
        container.innerHTML = `<div class="browser-empty">${emptyStateHtml(EMPTY_SVG_FILE, t('browser.no_items'))}</div>`;
        return;
    }

    // Column header row
    const header = document.createElement('div');
    header.className = 'browser-list-header';
    header.innerHTML = `
        <span></span>
        <span>${t('browser.list_header.name')}</span>
        <span>${t('browser.list_header.bitrate')}</span>
        <span>${t('browser.list_header.duration')}</span>
        <span>${t('browser.list_header.size')}</span>
        <span></span>
    `;
    container.appendChild(header);

    items.forEach((item, idx) => {
        const row = document.createElement('div');
        row.className = 'browser-list-item';
        row.style.setProperty('--item-index', Math.min(idx, 20));
        row.dataset.name = item.name;
        row.dataset.type = item.type;

        // Icon (small) with play overlay
        const icon = document.createElement('div');
        icon.className = 'browser-list-icon';

        if (item.is_media && item.type === 'audio') {
            const thumbnail = document.createElement('img');
            thumbnail.className = 'browser-list-thumbnail loading';
            thumbnail.alt = item.name;
            icon.appendChild(thumbnail);
            loadThumbnail(thumbnail, item.name);
        } else {
            icon.textContent = getFileIcon(item.type);
        }

        if (item.is_media) {
            const overlay = document.createElement('div');
            overlay.className = 'browser-list-play-overlay';
            overlay.innerHTML = '<svg viewBox="0 0 24 24"><path fill="currentColor" d="M8 5v14l11-7z"/></svg>';
            icon.appendChild(overlay);
        }
        row.appendChild(icon);

        // Name (show media title if available)
        const name = document.createElement('div');
        name.className = 'browser-list-name';
        name.textContent = item.title || item.name;
        row.appendChild(name);

        // Bitrate
        const br = document.createElement('div');
        br.className = 'browser-list-bitrate';
        br.textContent = formatBitrate(item.bitrate) || '';
        row.appendChild(br);

        // Duration
        const dur = document.createElement('div');
        dur.className = 'browser-list-duration';
        dur.textContent = formatDuration(item.duration) || '';
        row.appendChild(dur);

        // Size
        const size = document.createElement('div');
        size.className = 'browser-list-size';
        size.textContent = (item.size !== null && item.type !== 'folder') ? formatFileSize(item.size) : '';
        row.appendChild(size);

        // Download button
        if (item.is_media) {
            row.appendChild(createDownloadBtn(item.name, 'browser-list-download'));
        } else {
            row.appendChild(document.createElement('div'));
        }

        // Tooltip: show filename when title is displayed, or when name is ellipsed
        row.addEventListener('mouseenter', () => {
            if (item.title || name.scrollWidth > name.clientWidth) {
                row.title = item.name;
            } else {
                row.title = '';
            }
        });

        // Single click: play media or navigate folder
        row.onclick = () => {
            if (item.type === 'folder') {
                const newPath = currentPath === '/'
                    ? '/' + item.name
                    : currentPath + '/' + item.name;
                browsePath(currentFolderId, newPath);
            } else if (item.is_media) {
                playMediaFile(item.name);
            }
        };

        container.appendChild(row);
    });
}

function renderBrowserGrid(items, container) {
    container = container || document.getElementById('browserGrid');
    container.innerHTML = '';

    if (!items || items.length === 0) {
        container.innerHTML = `<div class="browser-empty">${emptyStateHtml(EMPTY_SVG_FILE, t('browser.no_items'))}</div>`;
        return;
    }

    items.forEach((item, idx) => {
        const div = document.createElement('div');
        div.className = 'browser-item';
        div.style.setProperty('--item-index', Math.min(idx, 20));
        div.dataset.name = item.name;
        div.dataset.type = item.type;

        // Type badge
        if (item.type !== 'folder') {
            const typeBadge = document.createElement('div');
            typeBadge.className = `browser-item-type ${item.type}`;
            typeBadge.innerHTML = getTypeBadgeIcon(item.type);
            div.appendChild(typeBadge);
        }

        // Thumbnail wrapper (for play overlay)
        const thumbWrapper = document.createElement('div');
        thumbWrapper.className = 'browser-thumb-wrapper';

        // Thumbnail or icon
        if (item.is_media && item.type === 'audio') {
            const thumbnail = document.createElement('img');
            thumbnail.className = 'browser-thumbnail loading';
            thumbnail.alt = item.name;
            thumbWrapper.appendChild(thumbnail);

            // Lazy load thumbnail
            loadThumbnail(thumbnail, item.name);
        } else {
            const iconEl = document.createElement('div');
            iconEl.className = 'browser-icon';
            iconEl.textContent = getFileIcon(item.type);
            thumbWrapper.appendChild(iconEl);
        }

        // Play overlay for media files
        if (item.is_media) {
            const overlay = document.createElement('div');
            overlay.className = 'browser-play-overlay';
            overlay.innerHTML = '<svg viewBox="0 0 24 24"><path fill="currentColor" d="M8 5v14l11-7z"/></svg>';
            thumbWrapper.appendChild(overlay);
        }

        div.appendChild(thumbWrapper);

        // Info
        const info = document.createElement('div');
        info.className = 'browser-item-info';

        const name = document.createElement('div');
        name.className = 'browser-item-name';
        name.textContent = item.title || item.name;
        info.appendChild(name);

        if (item.type !== 'folder') {
            const meta = document.createElement('div');
            meta.className = 'browser-item-meta';
            const parts = [];
            const duration = formatDuration(item.duration);
            if (duration) parts.push(duration);
            const bitrate = formatBitrate(item.bitrate);
            if (bitrate) parts.push(bitrate);
            if (item.size !== null) parts.push(formatFileSize(item.size));
            meta.textContent = parts.join(' \u00B7 ');
            if (parts.length) info.appendChild(meta);
        }

        div.appendChild(info);

        // Tooltip: show filename when title is displayed, or when name is ellipsed
        div.addEventListener('mouseenter', () => {
            if (item.title || name.scrollWidth > name.clientWidth || name.scrollHeight > name.clientHeight) {
                div.title = item.name;
            } else {
                div.title = '';
            }
        });

        // Single click: play media or navigate folder
        div.onclick = () => {
            if (item.type === 'folder') {
                const newPath = currentPath === '/'
                    ? '/' + item.name
                    : currentPath + '/' + item.name;
                browsePath(currentFolderId, newPath);
            } else if (item.is_media) {
                playMediaFile(item.name);
            }
        };

        container.appendChild(div);
    });
}

function getTypeBadgeIcon(type) {
    const svgs = {
        'audio': '<svg viewBox="0 0 24 24" width="10" height="10"><path fill="currentColor" d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z"/></svg>',
        'video': '<svg viewBox="0 0 24 24" width="10" height="10"><path fill="currentColor" d="M17 10.5V7c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h12c.55 0 1-.45 1-1v-3.5l4 4v-11l-4 4z"/></svg>',
    };
    return svgs[type] || '';
}

function getFileIcon(type) {
    const icons = {
        'folder': '\u{1F4C1}',
        'audio': '\u{1F3B5}',
        'video': '\u{1F3AC}',
        'other': '\u{1F4C4}'
    };
    return icons[type] || icons.other;
}

function formatFileSize(bytes) {
    if (bytes === 0) return '0 B';
    const k = 1024;
    const sizes = ['B', 'KB', 'MB', 'GB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return (bytes / Math.pow(k, i)).toFixed(1) + ' ' + sizes[i];
}

function formatDuration(seconds) {
    if (seconds == null || seconds <= 0) return null;
    const h = Math.floor(seconds / 3600);
    const m = Math.floor((seconds % 3600) / 60);
    const s = Math.floor(seconds % 60);
    if (h > 0) {
        return `${h}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
    }
    return `${m}:${String(s).padStart(2, '0')}`;
}

function formatBitrate(bps) {
    if (bps == null || bps <= 0) return null;
    return Math.round(bps / 1000) + ' kbps';
}

// Bump this whenever the user changes folder/path so in-flight fetches from
// the previous view can be ignored when they finally resolve.
let _browseGen = 0;
function bumpBrowseGen() { return ++_browseGen; }
function currentBrowseGen() { return _browseGen; }

function buildRelativeFilePath(relativePath, fileName) {
    const base = (relativePath === '/' || relativePath === '') ? '' : relativePath.replace(/\/$/, '');
    return base + '/' + fileName;
}

async function loadThumbnail(imgElement, fileName) {
    const myGen = currentBrowseGen();
    const folderId = currentFolderId;
    const relPath = buildRelativeFilePath(currentPath, fileName);
    const cacheKey = `${folderId}|${relPath}`;
    try {
        if (!hasCredentials()) return;
        // Note: the imgElement is intentionally NOT in the DOM yet when
        // renderBrowserGrid/renderBrowserList call us — it's still inside a
        // detached wrapper. Don't bail on isConnected here; rely on the
        // post-await checks below, which correctly catch navigation away.

        // Check cache first
        if (thumbnailCache.has(cacheKey)) {
            const cachedUrl = thumbnailCache.get(cacheKey);
            imgElement.onload = () => {
                if (!imgElement.isConnected) return;
                imgElement.classList.remove('loading');
                imgElement.classList.add('loaded');
            };
            imgElement.src = cachedUrl;
            return;
        }

        const params = new URLSearchParams({
            folder_id: folderId,
            path: relPath,
            size: 'medium',
        });
        const response = await fetch(
            `/api/browser/thumbnail?${params.toString()}`,
            { headers: getAuthHeaders() }
        );

        // Drop the response if the user has since navigated away.
        if (myGen !== currentBrowseGen() || !imgElement.isConnected) return;

        if (response.status === 200) {
            const blob = await response.blob();
            if (myGen !== currentBrowseGen() || !imgElement.isConnected) return;
            const url = URL.createObjectURL(blob);
            thumbnailCache.set(cacheKey, url);

            // Evict oldest entries when cache exceeds limit
            if (thumbnailCache.size > THUMBNAIL_CACHE_MAX) {
                const oldest = thumbnailCache.keys().next().value;
                URL.revokeObjectURL(thumbnailCache.get(oldest));
                thumbnailCache.delete(oldest);
            }

            imgElement.onload = () => {
                imgElement.classList.remove('loading');
                imgElement.classList.add('loaded');
            };

            if (imgElement.src && imgElement.src.startsWith('blob:')) {
                let isCached = false;
                for (const cachedUrl of thumbnailCache.values()) {
                    if (cachedUrl === imgElement.src) { isCached = true; break; }
                }
                if (!isCached) URL.revokeObjectURL(imgElement.src);
            }
            imgElement.src = url;
        } else {
            const parent = imgElement.parentElement;
            if (!parent) return;
            const isList = parent.classList.contains('browser-list-icon');
            imgElement.remove();
            if (isList) {
                parent.textContent = '\u{1F3B5}';
            } else {
                const iconEl = document.createElement('div');
                iconEl.className = 'browser-icon';
                iconEl.textContent = '\u{1F3B5}';
                parent.insertBefore(iconEl, parent.firstChild);
            }
        }
    } catch (error) {
        console.error('Error loading thumbnail:', error);
        if (imgElement.isConnected) imgElement.classList.remove('loading');
    }
}

function buildAbsolutePath(folderId, relativePath, fileName) {
    const folderPath = mediaFolders[folderId].path;
    // Detect separator from folder path
    const sep = folderPath.includes('/') ? '/' : '\\';
    const fullRelative = relativePath === '/'
        ? sep + fileName
        : relativePath.replace(/[/\\]/g, sep) + sep + fileName;
    return folderPath + fullRelative;
}

let playInProgress = false;

async function playMediaFile(fileName) {
    if (playInProgress) return;
    playInProgress = true;
    try {
        if (!hasCredentials()) return;

        const relativePath = buildRelativeFilePath(currentPath, fileName);

        const response = await fetch('/api/browser/play', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json', ...getAuthHeaders() },
            body: JSON.stringify({ folder_id: currentFolderId, path: relativePath })
        });

        if (!response.ok) throw new Error('Failed to play file');

        showToast(t('browser.play_success', { filename: fileName }), 'success');
    } catch (error) {
        console.error('Error playing file:', error);
        showToast(t('browser.play_error'), 'error');
    } finally {
        playInProgress = false;
    }
}

export async function playAllFolder() {
    if (playInProgress) return;
    playInProgress = true;
    const btn = document.getElementById('playAllBtn');
    if (btn) btn.disabled = true;
    try {
        if (!hasCredentials() || !currentFolderId) return;

        const response = await fetch('/api/browser/play-folder', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json', ...getAuthHeaders() },
            body: JSON.stringify({ folder_id: currentFolderId, path: currentPath })
        });

        if (!response.ok) {
            const err = await response.json().catch(() => ({}));
            throw new Error(err.detail || 'Failed to play folder');
        }

        const data = await response.json();
        showToast(t('browser.play_all_success', { count: data.count }), 'success');
    } catch (error) {
        console.error('Error playing folder:', error);
        showToast(t('browser.play_all_error'), 'error');
    } finally {
        playInProgress = false;
        if (btn) btn.disabled = false;
    }
}

export async function downloadFile(fileName, event) {
    if (event) event.stopPropagation();
    if (!hasCredentials()) return;

    const fullPath = currentPath === '/'
        ? '/' + fileName
        : currentPath + '/' + fileName;
    const encodedPath = encodeURIComponent(fullPath);

    try {
        const response = await fetch(
            `/api/browser/download?folder_id=${currentFolderId}&path=${encodedPath}`,
            { headers: getAuthHeaders() }
        );
        if (!response.ok) throw new Error('Download failed');

        const blob = await response.blob();
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = fileName;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);
    } catch (error) {
        console.error('Download error:', error);
        showToast(t('browser.download_error'), 'error');
    }
}

function createDownloadBtn(fileName, cssClass) {
    const btn = document.createElement('button');
    btn.className = cssClass;
    btn.innerHTML = '<svg viewBox="0 0 24 24" width="14" height="14"><path fill="currentColor" d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/></svg>';
    btn.title = t('browser.download');
    btn.onclick = (e) => downloadFile(fileName, e);
    return btn;
}

function renderPagination() {
    const pagination = document.getElementById('browserPagination');
    const prevBtn = document.getElementById('prevPage');
    const nextBtn = document.getElementById('nextPage');
    const pageInput = document.getElementById('pageInput');
    const pageTotal = document.getElementById('pageTotal');
    const showingEl = document.getElementById('paginationShowing');

    const totalPages = Math.ceil(totalItems / itemsPerPage);
    const currentPage = Math.floor(currentOffset / itemsPerPage) + 1;

    if (totalPages <= 1) {
        pagination.style.display = 'none';
        return;
    }

    pagination.style.display = 'flex';
    pageInput.value = currentPage;
    pageInput.max = totalPages;
    pageTotal.textContent = `/ ${totalPages}`;

    // "Showing X-Y of Z"
    if (showingEl) {
        const from = currentOffset + 1;
        const to = Math.min(currentOffset + itemsPerPage, totalItems);
        showingEl.textContent = t('browser.showing_items', { from, to, total: totalItems });
    }

    prevBtn.disabled = currentPage === 1;
    nextBtn.disabled = currentPage === totalPages;
}

export function previousPage() {
    if (currentOffset >= itemsPerPage) {
        browsePath(currentFolderId, currentPath, currentOffset - itemsPerPage);
    }
}

export function nextPage() {
    if (currentOffset + itemsPerPage < totalItems) {
        browsePath(currentFolderId, currentPath, currentOffset + itemsPerPage);
    }
}

export function refreshBrowser() {
    if (currentFolderId) {
        browsePath(currentFolderId, currentPath, currentOffset, true);
    } else {
        loadMediaFolders();
    }
}

// Browser search
export function onBrowserSearch() {
    const input = document.getElementById('browserSearchInput');
    const clearBtn = document.getElementById('browserSearchClear');
    const term = input.value.trim();

    clearBtn.style.display = term ? 'flex' : 'none';

    // Debounce: wait 200ms after typing stops
    if (browserSearchTimer) clearTimeout(browserSearchTimer);
    browserSearchTimer = setTimeout(() => {
        browserSearchTerm = term.toLowerCase();
        applyBrowserSearch();
    }, SEARCH_DEBOUNCE_MS);
}

export function clearBrowserSearch() {
    const input = document.getElementById('browserSearchInput');
    input.value = '';
    document.getElementById('browserSearchClear').style.display = 'none';
    browserSearchTerm = '';
    applyBrowserSearch();
    input.focus();
}

function applyBrowserSearch() {
    if (!cachedItems) return;

    if (!browserSearchTerm) {
        renderBrowserItems(cachedItems);
        return;
    }

    const filtered = cachedItems.filter(item =>
        item.name.toLowerCase().includes(browserSearchTerm) ||
        (item.title && item.title.toLowerCase().includes(browserSearchTerm))
    );
    renderBrowserItems(filtered);
}

function showBrowserSearch(visible) {
    document.getElementById('browserSearchWrapper').style.display = visible ? '' : 'none';
    if (!visible) {
        document.getElementById('browserSearchInput').value = '';
        document.getElementById('browserSearchClear').style.display = 'none';
        browserSearchTerm = '';
    }
}

export function setViewMode(mode) {
    if (mode === viewMode) return;
    viewMode = mode;
    localStorage.setItem('mediaBrowser.viewMode', mode);

    // Update toggle buttons
    document.querySelectorAll('.view-toggle-btn').forEach(btn => btn.classList.remove('active'));
    const btnId = mode === 'list' ? 'viewListBtn' : mode === 'compact' ? 'viewCompactBtn' : 'viewGridBtn';
    document.getElementById(btnId).classList.add('active');

    // Re-render current view from cache (no network request)
    if (currentFolderId && cachedItems) {
        applyBrowserSearch();
    } else {
        showRootFolders();
    }
}

export function onItemsPerPageChanged() {
    const select = document.getElementById('itemsPerPageSelect');
    itemsPerPage = parseInt(select.value);
    localStorage.setItem('mediaBrowser.itemsPerPage', itemsPerPage);

    // Reset to first page and reload
    if (currentFolderId) {
        currentOffset = 0;
        browsePath(currentFolderId, currentPath, 0);
    }
}

export function goToPage() {
    const pageInput = document.getElementById('pageInput');
    const totalPages = Math.ceil(totalItems / itemsPerPage);
    let page = parseInt(pageInput.value);

    if (isNaN(page) || page < 1) page = 1;
    if (page > totalPages) page = totalPages;

    pageInput.value = page;
    const newOffset = (page - 1) * itemsPerPage;
    if (newOffset !== currentOffset) {
        browsePath(currentFolderId, currentPath, newOffset);
    }
}

export function initBrowserToolbar() {
    // Restore view mode
    const savedViewMode = localStorage.getItem('mediaBrowser.viewMode') || 'grid';
    viewMode = savedViewMode;
    document.querySelectorAll('.view-toggle-btn').forEach(btn => btn.classList.remove('active'));
    const btnId = savedViewMode === 'list' ? 'viewListBtn' : savedViewMode === 'compact' ? 'viewCompactBtn' : 'viewGridBtn';
    document.getElementById(btnId).classList.add('active');

    // Restore items per page
    const savedItemsPerPage = localStorage.getItem('mediaBrowser.itemsPerPage');
    if (savedItemsPerPage) {
        itemsPerPage = parseInt(savedItemsPerPage);
        document.getElementById('itemsPerPageSelect').value = savedItemsPerPage;
    }
}

function clearBrowserGrid() {
    const grid = document.getElementById('browserGrid');
    grid.innerHTML = `<div class="browser-empty">${emptyStateHtml(EMPTY_SVG_FOLDER, t('browser.no_folder_selected'))}</div>`;
    document.getElementById('breadcrumb').innerHTML = '';
    document.getElementById('browserPagination').style.display = 'none';
    document.getElementById('playAllBtn').style.display = 'none';
}

// LocalStorage for last path
function saveLastBrowserPath(folderId, path) {
    try {
        localStorage.setItem('mediaBrowser.lastFolderId', folderId);
        localStorage.setItem('mediaBrowser.lastPath', path);
    } catch (e) {
        console.error('Failed to save last browser path:', e);
    }
}

function loadLastBrowserPath() {
    try {
        const lastFolderId = localStorage.getItem('mediaBrowser.lastFolderId');
        const lastPath = localStorage.getItem('mediaBrowser.lastPath');

        if (lastFolderId && mediaFolders[lastFolderId]) {
            currentFolderId = lastFolderId;
            browsePath(lastFolderId, lastPath || '');
        } else {
            showRootFolders();
        }
    } catch (e) {
        console.error('Failed to load last browser path:', e);
        showRootFolders();
    }
}

// Folder Management — Settings table

export function loadFoldersTable() {
    const tbody = document.getElementById('foldersTableBody');
    if (!tbody) return;

    const entries = Object.entries(mediaFolders);
    if (entries.length === 0) {
        tbody.innerHTML = `<tr><td colspan="5" class="empty-state">
            <div class="empty-state-illustration">
                <svg viewBox="0 0 64 64"><path d="M8 16h20l4-6h20a4 4 0 014 4v36a4 4 0 01-4 4H8a4 4 0 01-4-4V20a4 4 0 014-4z"/><path d="M4 24h56" stroke-dasharray="4 3" opacity="0.4"/></svg>
                <p data-i18n="browser.folders_empty">${t('browser.folders_empty')}</p>
            </div></td></tr>`;
        return;
    }

    tbody.innerHTML = entries.map(([id, folder]) => {
        const available = folder.available !== false;
        const statusIcon = available
            ? '<span class="status-dot status-online">' + t('browser.folder_available') + '</span>'
            : '<span class="status-dot status-offline">' + t('browser.folder_unavailable') + '</span>';
        const enabledBadge = folder.enabled
            ? ''
            : ' <span class="folder-disabled-badge">' + t('browser.folder_disabled') + '</span>';
        return `<tr>
            <td>${escapeHtml(id)}${enabledBadge}</td>
            <td>${escapeHtml(folder.label)}</td>
            <td class="path-cell" title="${escapeHtml(folder.path)}">${escapeHtml(folder.path)}</td>
            <td>${statusIcon}</td>
            <td class="actions-cell">
                <button class="btn-icon" data-action="edit" data-folder-id="${escapeHtml(id)}" title="${t('browser.folder_edit')}">
                    <svg viewBox="0 0 24 24" width="16" height="16"><path fill="currentColor" d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/></svg>
                </button>
                <button class="btn-icon btn-danger-icon" data-action="delete" data-folder-id="${escapeHtml(id)}" title="${t('browser.folder_delete')}">
                    <svg viewBox="0 0 24 24" width="16" height="16"><path fill="currentColor" d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/></svg>
                </button>
            </td>
        </tr>`;
    }).join('');
}

export function showAddFolderDialog() {
    document.getElementById('folderDialogTitle').textContent = t('browser.folder_dialog.title_add');
    document.getElementById('folderIsEdit').value = '';
    document.getElementById('folderOriginalId').value = '';
    document.getElementById('folderId').value = '';
    document.getElementById('folderId').disabled = false;
    document.getElementById('folderLabel').value = '';
    document.getElementById('folderPath').value = '';
    document.getElementById('folderEnabled').checked = true;
    document.getElementById('folderDialog').showModal();
}

export function showEditFolderDialog(folderId) {
    const folder = mediaFolders[folderId];
    if (!folder) return;

    document.getElementById('folderDialogTitle').textContent = t('browser.folder_dialog.title_edit');
    document.getElementById('folderIsEdit').value = '1';
    document.getElementById('folderOriginalId').value = folderId;
    document.getElementById('folderId').value = folderId;
    document.getElementById('folderId').disabled = true;
    document.getElementById('folderLabel').value = folder.label;
    document.getElementById('folderPath').value = folder.path;
    document.getElementById('folderEnabled').checked = folder.enabled;
    document.getElementById('folderDialog').showModal();
}

export function closeFolderDialog() {
    closeDialog(document.getElementById('folderDialog'));
}

export async function saveFolder(event) {
    event.preventDefault();

    const isEdit = document.getElementById('folderIsEdit').value === '1';
    const folderId = isEdit
        ? document.getElementById('folderOriginalId').value
        : document.getElementById('folderId').value.trim();
    const label = document.getElementById('folderLabel').value.trim();
    const path = document.getElementById('folderPath').value.trim();
    const enabled = document.getElementById('folderEnabled').checked;

    if (!folderId || !label || !path) return;

    const submitBtn = document.querySelector('#folderForm button[type="submit"]');
    if (submitBtn) submitBtn.disabled = true;

    try {
        let response;
        if (isEdit) {
            response = await fetch(`/api/browser/folders/update/${encodeURIComponent(folderId)}`, {
                method: 'PUT',
                headers: { 'Content-Type': 'application/json', ...getAuthHeaders() },
                body: JSON.stringify({ label, path, enabled }),
            });
        } else {
            response = await fetch('/api/browser/folders/create', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json', ...getAuthHeaders() },
                body: JSON.stringify({ folder_id: folderId, label, path, enabled }),
            });
        }

        if (response.ok) {
            closeFolderDialog();
            showToast(t(isEdit ? 'browser.folder_updated' : 'browser.folder_created'), 'success');
            await loadMediaFolders();
        } else {
            const result = await response.json().catch(() => ({}));
            showToast(result.detail || t('browser.folder_save_error'), 'error');
        }
    } catch (error) {
        console.error('Error saving folder:', error);
        showToast(t('browser.folder_save_error'), 'error');
    } finally {
        if (submitBtn) submitBtn.disabled = false;
    }
}

export async function deleteFolderConfirm(folderId) {
    if (!await showConfirm(t('browser.folder_confirm_delete', { name: folderId }))) {
        return;
    }

    try {
        const response = await fetch(`/api/browser/folders/delete/${encodeURIComponent(folderId)}`, {
            method: 'DELETE',
            headers: getAuthHeaders(),
        });

        if (response.ok) {
            showToast(t('browser.folder_deleted'), 'success');
            await loadMediaFolders();
        } else {
            const result = await response.json().catch(() => ({}));
            showToast(result.detail || t('browser.folder_delete_error'), 'error');
        }
    } catch (error) {
        console.error('Error deleting folder:', error);
        showToast(t('browser.folder_delete_error'), 'error');
    }
}

// Legacy stub — now handled via settings table
export function showManageFoldersDialog() {
    if (managementEnabled) {
        // Switch to settings tab and scroll to the folders section
        const switchTabFn = window.switchTab;
        if (switchTabFn) switchTabFn('settings');
        setTimeout(() => {
            const section = document.getElementById('mediaFoldersSection');
            if (section) {
                section.setAttribute('open', '');
                section.scrollIntoView({ behavior: 'smooth' });
            }
        }, 100);
    } else {
        showToast(t('browser.manage_folders_hint'), 'info');
    }
}
