/**
 * File tree rendering and navigation
 */

// Cache for lazily loaded CDN libraries
const loadedLibraries = new Map();

/**
 * Lazily load a script from CDN. Returns a promise that resolves when loaded.
 * Caches the promise so subsequent calls return immediately.
 */
function loadLibrary(url) {
    if (loadedLibraries.has(url)) return loadedLibraries.get(url);
    const promise = new Promise((resolve, reject) => {
        const script = document.createElement('script');
        script.src = url;
        script.onload = resolve;
        script.onerror = () => reject(new Error(`Failed to load library: ${url}`));
        document.head.appendChild(script);
    });
    loadedLibraries.set(url, promise);
    return promise;
}

/**
 * Render the file tree in the UI
 */
/**
 * Create action buttons for file/directory items
 * @param {string} filePath - Full path of the file/dir
 * @param {string} type - 'file' or 'directory'
 */
function createActionButtons(filePath, type) {
    const actionsDiv = document.createElement('div');
    actionsDiv.className = 'tree-actions';

    // Server mode now supports full CRUD via the file API — drop the
    // legacy short-circuit that hid the rename/delete/new-file actions.

    if (type === 'directory') {
        // Directory: + (new file) + ✕ (delete)
        const newFileBtn = document.createElement('button');
        newFileBtn.className = 'tree-btn';
        newFileBtn.setAttribute('title', 'New file');
        newFileBtn.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 5v14M5 12h14"/></svg>';
        newFileBtn.onclick = (e) => {
            e.stopPropagation();
            createNewFile(filePath);
        };

        const deleteBtn = document.createElement('button');
        deleteBtn.className = 'tree-btn tree-btn--danger';
        deleteBtn.setAttribute('title', 'Delete');
        deleteBtn.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>';
        deleteBtn.onclick = (e) => {
            e.stopPropagation();
            deleteEntry(filePath, true);
        };

        actionsDiv.appendChild(newFileBtn);
        actionsDiv.appendChild(deleteBtn);
    } else {
        // File: ✎ (rename) + ✕ (delete)
        const renameBtn = document.createElement('button');
        renameBtn.className = 'tree-btn';
        renameBtn.setAttribute('title', 'Rename');
        renameBtn.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M17 3a2.828 2.828 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z"/></svg>';
        renameBtn.onclick = (e) => {
            e.stopPropagation();
            renameEntry(filePath, false);
        };

        const deleteBtn = document.createElement('button');
        deleteBtn.className = 'tree-btn tree-btn--danger';
        deleteBtn.setAttribute('title', 'Delete');
        deleteBtn.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>';
        deleteBtn.onclick = (e) => {
            e.stopPropagation();
            deleteEntry(filePath, false);
        };

        actionsDiv.appendChild(renameBtn);
        actionsDiv.appendChild(deleteBtn);
    }

    return actionsDiv;
}

function renderFileTree() {
    const fileTreeElement = document.getElementById('file-tree');
    if (!fileTreeElement) return;

    fileTreeElement.innerHTML = '';
    
    // Always show scratchpad at top
    const scratchpadElement = document.createElement('div');
    scratchpadElement.className = 'file-item tree-row px-2 py-1 cursor-pointer rounded hover:bg-gray-100 dark:hover:bg-gray-800 border-b border-gray-200 dark:border-gray-700 mb-2';
    scratchpadElement.dataset.type = 'file';
    scratchpadElement.dataset.path = SCRATCHPAD_ID;
    scratchpadElement.dataset.name = 'Scratchpad';

    const scratchLabel = document.createElement('span');
    scratchLabel.className = 'tree-row__label';
    scratchLabel.innerHTML = '<span class="tree-row__name"><div class="filename-main">📝 Scratchpad</div><div class="filename-secondary">Quick notes — no directory needed</div></span>';
    scratchpadElement.appendChild(scratchLabel);

    const scratchActions = document.createElement('div');
    scratchActions.className = 'tree-actions tree-actions--always';

    const scratchDownloadBtn = document.createElement('button');
    scratchDownloadBtn.id = 'scratchpad-download-btn';
    scratchDownloadBtn.className = 'tree-btn';
    scratchDownloadBtn.title = 'Download scratchpad as a Markdown file';
    scratchDownloadBtn.setAttribute('aria-label', 'Download scratchpad');
    scratchDownloadBtn.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v12"/><path d="M7 10l5 5 5-5"/><path d="M5 21h14"/></svg>';
    scratchDownloadBtn.disabled = true;
    scratchDownloadBtn.classList.add('is-disabled');
    scratchDownloadBtn.onclick = (e) => {
        e.stopPropagation();
        if (scratchDownloadBtn.disabled) return;
        downloadScratchpad();
    };
    scratchActions.appendChild(scratchDownloadBtn);
    scratchpadElement.appendChild(scratchActions);

    scratchpadElement.addEventListener('click', (event) => {
        event.stopPropagation();
        openScratchpad();
        document.querySelectorAll('.file-item').forEach(el => el.classList.remove('active-file'));
        scratchpadElement.classList.add('active-file');
        updateScratchpadDownloadState();
    });

    fileTreeElement.appendChild(scratchpadElement);
    // Sync button state with current scratchpad content (re-renders preserve it)
    updateScratchpadDownloadState();

    function createFileTreeHTML(directory, parentElement, path = '') {
        if (!directory || !directory.entries) return;

        // Sort entries: files first, then directories, alphabetically
        const sortedEntries = Object.entries(directory.entries).sort((a, b) => {
            const [nameA, itemA] = a;
            const [nameB, itemB] = b;

            if (itemA.type !== itemB.type) {
                return itemA.type === 'file' ? -1 : 1;
            }

            return nameA.localeCompare(nameB);
        });

        for (const [name, item] of sortedEntries) {
            if (item.type === 'directory') {
                const dirElement = document.createElement('div');
                dirElement.className = 'directory-item tree-row px-2 py-1 cursor-pointer rounded hover:bg-gray-100 dark:hover:bg-gray-800 collapsed';
                dirElement.dataset.type = 'directory';
                const currentPath = path ? `${path}/${name}` : name;
                dirElement.dataset.path = currentPath;

                const dirIcon = document.createElement('span');
                dirIcon.className = 'dir-icon mr-1';
                dirIcon.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"></polyline></svg>';

                const dirName = document.createElement('span');
                dirName.className = 'tree-row__name';
                const parsedFolder = zddc.parseFolder(name);
                if (parsedFolder && parsedFolder.valid) {
                    const meta = `${parsedFolder.trackingNumber} (${parsedFolder.status}) — ${parsedFolder.date}`;
                    dirName.innerHTML = `<div class="filename-main">📁 ${escapeHtml(parsedFolder.title)}</div><div class="filename-secondary">${escapeHtml(meta)}</div>`;
                } else {
                    // Non-ZDDC folder: still wrap in filename-main so
                    // typography matches the two-line entries (same font
                    // size + weight; just no secondary line).
                    dirName.innerHTML = `<div class="filename-main">📁 ${escapeHtml(name)}</div>`;
                }

                const dirLabel = document.createElement('span');
                dirLabel.className = 'tree-row__label';
                dirLabel.appendChild(dirIcon);
                dirLabel.appendChild(dirName);

                const dirActions = createActionButtons(currentPath, 'directory');

                dirElement.appendChild(dirLabel);
                dirElement.appendChild(dirActions);
                parentElement.appendChild(dirElement);

                const contentsElement = document.createElement('div');
                contentsElement.className = 'directory-contents ml-4';
                contentsElement.style.display = 'none';
                parentElement.appendChild(contentsElement);

                dirElement.addEventListener('click', (event) => {
                    event.stopPropagation();
                    dirElement.classList.toggle('collapsed');

                    const contents = dirElement.nextElementSibling;
                    if (contents && contents.classList.contains('directory-contents')) {
                        contents.style.display = dirElement.classList.contains('collapsed') ? 'none' : 'block';
                    }
                });

                createFileTreeHTML(item, contentsElement, currentPath);
            } else if (item.type === 'file') {
                const fileElement = document.createElement('div');
                fileElement.className = 'file-item tree-row px-2 py-1 cursor-pointer rounded hover:bg-gray-100 dark:hover:bg-gray-800';
                fileElement.dataset.type = 'file';
                const filePath = path ? `${path}/${name}` : name;
                fileElement.dataset.path = filePath;
                fileElement.dataset.name = name;

                const fileIcon = getFileTypeIcon(name);

                // Build the inner two-line text inside a tree-row__name
                // wrapper (column-flex). ZDDC-conforming filenames split
                // into title + meta; "Title - filename.ext" pattern uses
                // the dash as the same split. Plain names get a single
                // line via filename-main only — same wrapper, just no
                // secondary div, so the layout stays consistent.
                let fileNameInner;
                const parsed = zddc.parseFilename(name);
                if (parsed && parsed.valid) {
                    const titleDisplay = escapeHtml(parsed.title);
                    const metaDisplay = escapeHtml(`${parsed.trackingNumber}_${parsed.revision} (${parsed.status})`);
                    fileNameInner = `<div class="filename-main">${fileIcon} ${titleDisplay}</div><div class="filename-secondary">${metaDisplay}</div>`;
                } else if (name.includes(' - ')) {
                    const dashIdx = name.lastIndexOf(' - ');
                    const secondary = escapeHtml(name.substring(0, dashIdx));
                    const primary = escapeHtml(name.substring(dashIdx + 3).replace(/\.[^.]+$/, ''));
                    fileNameInner = `<div class="filename-main">${fileIcon} ${primary}</div><div class="filename-secondary">${secondary}</div>`;
                } else {
                    fileNameInner = `<div class="filename-main">${fileIcon} ${escapeHtml(name)}</div>`;
                }

                const fileLabel = document.createElement('span');
                fileLabel.className = 'tree-row__label';
                fileLabel.innerHTML = `<span class="tree-row__name">${fileNameInner}</span>`;

                const fileActions = createActionButtons(filePath, 'file');

                fileElement.innerHTML = '';
                fileElement.appendChild(fileLabel);
                fileElement.appendChild(fileActions);

                fileElement.addEventListener('click', (event) => {
                    event.stopPropagation();
                    handleFileClick(item.handle, filePath, fileElement);
                });

                parentElement.appendChild(fileElement);
            }
        }
    }

    createFileTreeHTML(fileTree, fileTreeElement);
}

/**
 * Handle click on a file in the file tree
 * @param {FileSystemFileHandle} fileHandle - The file handle
 * @param {string} filePath - Path of the file
 * @param {HTMLElement} fileElement - The clicked element
 */
async function handleFileClick(fileHandle, filePath, fileElement) {
    try {
        currentFileHandle = fileHandle;

        // Remove active class from all file items
        const allFileItems = document.querySelectorAll('.file-item');
        allFileItems.forEach(item => {
            item.classList.remove('active-file');
            item.style.backgroundColor = '';
            item.style.color = '';
        });

        // Add active class to clicked file
        fileElement.classList.add('active-file');
        fileElement.style.backgroundColor = '#3b82f6';
        fileElement.style.color = 'white';

        await displayFileContent(fileHandle, filePath);

    } catch (error) {
        console.error('Error handling file click:', error);
        alert(`Error opening file: ${error.message}`);
    }
}

/**
 * Display file content in main area
 * @param {FileSystemFileHandle} fileHandle - File handle
 * @param {string} filePath - Path of the file
 */
async function displayFileContent(fileHandle, filePath) {
    try {
        currentFileHandle = fileHandle;

        const file = await fileHandle.getFile();
        const fileName = file.name;
        const lastModified = file.lastModified;

        document.getElementById('welcome-screen').classList.add('hidden');
        document.getElementById('content-container').classList.remove('hidden');

        const lower = fileName.toLowerCase();
        const lastDot = lower.lastIndexOf('.');
        const ext = lastDot >= 0 ? lower.substring(lastDot + 1) : '';

        const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.svg'];
        const isImage = imageExtensions.some(e => lower.endsWith(e));
        const isTiff = window.zddc && window.zddc.preview && window.zddc.preview.isTiff(ext);
        const isZip = lower.endsWith('.zip');
        const isHtml = lower.endsWith('.html') || lower.endsWith('.htm');
        const isDocx = lower.endsWith('.docx');
        const isXlsx = lower.endsWith('.xlsx') || lower.endsWith('.xls');
        const isPdf = lower.endsWith('.pdf');

        if (isImage) {
            displayImagePreview(file, filePath, fileName, fileHandle, lastModified);
        } else if (isTiff) {
            displayTiffPreview(file, filePath, fileName, fileHandle, lastModified);
        } else if (isZip) {
            displayZipPreview(file, filePath, fileName, fileHandle, lastModified);
        } else if (isHtml) {
            displayHtmlPreview(file, filePath, fileName, fileHandle, lastModified);
        } else if (isDocx) {
            displayDocxPreview(file, filePath, fileName, fileHandle, lastModified);
        } else if (isXlsx) {
            displayXlsxPreview(file, filePath, fileName, fileHandle, lastModified);
        } else if (isPdf) {
            displayPdfPreview(file, filePath, fileName, fileHandle, lastModified);
        } else {
            const content = await file.text();

            if (fileName.toLowerCase().endsWith('.md')) {
                initializeEditor(content, true, filePath, fileName, fileHandle, lastModified);
            } else {
                initializeEditor(content, false, filePath, fileName, fileHandle, lastModified);
            }
        }
    } catch (error) {
        console.error('Error displaying file content:', error);
        alert(`Error opening file: ${error.message}`);
    }
}

/**
 * Display image preview
 */
async function displayImagePreview(file, filePath, fileName, fileHandle, lastModified) {
    const contentContainer = document.getElementById('content-container');
    if (!contentContainer) {
        alert('Error: content-container element not found!');
        return;
    }

    document.querySelectorAll('.file-view-container').forEach(container => {
        container.style.display = 'none';
    });

    if (editorInstances.has(filePath)) {
        const existingInstance = editorInstances.get(filePath);
        if (existingInstance.fileViewContainer) {
            existingInstance.fileViewContainer.style.display = 'flex';
        }
        return;
    }

    const fileViewContainer = document.createElement('div');
    fileViewContainer.className = 'file-view-container flex flex-col h-full';

    const fileHeader = document.createElement('div');
    fileHeader.className = 'file-header flex justify-between items-center px-4 py-2 bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-200 font-medium border-b border-gray-200 dark:border-gray-700';

    const fileTitle = document.createElement('span');
    fileTitle.textContent = fileName || 'No file selected';
    fileHeader.appendChild(fileTitle);

    fileViewContainer.appendChild(fileHeader);

    const imageContainer = document.createElement('div');
    imageContainer.className = 'image-preview-container flex-1 overflow-auto p-4';

    const imageElement = document.createElement('img');
    imageElement.className = 'image-preview';
    imageElement.alt = fileName;

    const objectUrl = URL.createObjectURL(file);
    imageElement.src = objectUrl;

    imageContainer.appendChild(imageElement);
    fileViewContainer.appendChild(imageContainer);

    contentContainer.appendChild(fileViewContainer);

    const instanceData = {
        fileViewContainer: fileViewContainer,
        fileHandle: fileHandle,
        lastModified: lastModified,
        isDirty: false,
        objectUrl: objectUrl
    };

    editorInstances.set(filePath, instanceData);
}

/**
 * Display TIFF preview using shared zddc.preview.renderTiff (UTIF.js + canvas).
 */
async function displayTiffPreview(file, filePath, fileName, fileHandle, lastModified) {
    const contentContainer = document.getElementById('content-container');
    if (!contentContainer) return;

    document.querySelectorAll('.file-view-container').forEach(c => { c.style.display = 'none'; });

    if (editorInstances.has(filePath)) {
        const existing = editorInstances.get(filePath);
        if (existing.fileViewContainer) existing.fileViewContainer.style.display = 'flex';
        return;
    }

    const fileViewContainer = document.createElement('div');
    fileViewContainer.className = 'file-view-container flex flex-col h-full';

    const fileHeader = document.createElement('div');
    fileHeader.className = 'file-header flex justify-between items-center px-4 py-2 bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-200 font-medium border-b border-gray-200 dark:border-gray-700';
    const fileTitle = document.createElement('span');
    fileTitle.textContent = fileName || 'No file selected';
    fileHeader.appendChild(fileTitle);
    fileViewContainer.appendChild(fileHeader);

    const tiffContainer = document.createElement('div');
    tiffContainer.className = 'flex-1 min-h-0';
    tiffContainer.style.display = 'flex';
    tiffContainer.style.flexDirection = 'column';
    fileViewContainer.appendChild(tiffContainer);

    contentContainer.appendChild(fileViewContainer);

    try {
        const arrayBuffer = await file.arrayBuffer();
        await window.zddc.preview.renderTiff(document, tiffContainer, arrayBuffer, { fileName: fileName });
    } catch (err) {
        console.error('Error rendering TIFF:', err);
        tiffContainer.textContent = 'Error rendering TIFF: ' + (err.message || err);
    }

    editorInstances.set(filePath, { fileViewContainer, fileHandle, lastModified, isDirty: false });
}

/**
 * Display ZIP listing using shared zddc.preview.renderZipListing.
 */
async function displayZipPreview(file, filePath, fileName, fileHandle, lastModified) {
    const contentContainer = document.getElementById('content-container');
    if (!contentContainer) return;

    document.querySelectorAll('.file-view-container').forEach(c => { c.style.display = 'none'; });

    if (editorInstances.has(filePath)) {
        const existing = editorInstances.get(filePath);
        if (existing.fileViewContainer) existing.fileViewContainer.style.display = 'flex';
        return;
    }

    const fileViewContainer = document.createElement('div');
    fileViewContainer.className = 'file-view-container flex flex-col h-full';

    const fileHeader = document.createElement('div');
    fileHeader.className = 'file-header flex justify-between items-center px-4 py-2 bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-200 font-medium border-b border-gray-200 dark:border-gray-700';
    const fileTitle = document.createElement('span');
    fileTitle.textContent = fileName || 'No file selected';
    fileHeader.appendChild(fileTitle);
    fileViewContainer.appendChild(fileHeader);

    const zipContainer = document.createElement('div');
    zipContainer.className = 'flex-1 min-h-0';
    zipContainer.style.display = 'flex';
    zipContainer.style.flexDirection = 'column';
    fileViewContainer.appendChild(zipContainer);

    contentContainer.appendChild(fileViewContainer);

    try {
        const arrayBuffer = await file.arrayBuffer();
        await window.zddc.preview.renderZipListing(document, zipContainer, arrayBuffer, { fileName: fileName });
    } catch (err) {
        console.error('Error rendering ZIP listing:', err);
        zipContainer.textContent = 'Error reading ZIP: ' + (err.message || err);
    }

    editorInstances.set(filePath, { fileViewContainer, fileHandle, lastModified, isDirty: false });
}

/**
 * Display HTML preview in sandboxed iframe
 */
async function displayHtmlPreview(file, filePath, fileName, fileHandle, lastModified) {
    const contentContainer = document.getElementById('content-container');
    if (!contentContainer) {
        alert('Error: content-container element not found!');
        return;
    }

    document.querySelectorAll('.file-view-container').forEach(container => {
        container.style.display = 'none';
    });

    if (editorInstances.has(filePath)) {
        const existingInstance = editorInstances.get(filePath);
        if (existingInstance.fileViewContainer) {
            existingInstance.fileViewContainer.style.display = 'flex';
        }
        return;
    }

    const htmlContent = await file.text();

    const fileViewContainer = document.createElement('div');
    fileViewContainer.className = 'file-view-container flex flex-col h-full';

    const fileHeader = document.createElement('div');
    fileHeader.className = 'file-header flex justify-between items-center px-4 py-2 bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-200 font-medium border-b border-gray-200 dark:border-gray-700';

    const fileTitle = document.createElement('span');
    fileTitle.textContent = fileName || 'No file selected';
    fileHeader.appendChild(fileTitle);

    fileViewContainer.appendChild(fileHeader);

    const htmlContainer = document.createElement('div');
    htmlContainer.className = 'html-preview-container flex-1 overflow-hidden';

    const iframe = document.createElement('iframe');
    iframe.className = 'html-preview-iframe w-full h-full border-0';

    iframe.setAttribute('sandbox', 'allow-same-origin allow-scripts allow-forms allow-popups allow-modals');
    iframe.setAttribute('loading', 'lazy');

    iframe.srcdoc = htmlContent;

    htmlContainer.appendChild(iframe);
    fileViewContainer.appendChild(htmlContainer);

    contentContainer.appendChild(fileViewContainer);

    const instanceData = {
        fileViewContainer: fileViewContainer,
        fileHandle: fileHandle,
        lastModified: lastModified,
        isDirty: false,
        iframe: iframe
    };

    editorInstances.set(filePath, instanceData);

    iframe.addEventListener('load', () => {
        try {
            const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
            if (iframeDoc) {
                iframeDoc.addEventListener('click', function (e) {
                    const link = e.target.closest('a');
                    if (link && link.getAttribute('href')) {
                        const href = link.getAttribute('href');
                        if (href.startsWith('#')) {
                            e.preventDefault();
                            const targetId = href.substring(1);
                            const targetElement = iframeDoc.getElementById(targetId);
                            if (targetElement) {
                                targetElement.scrollIntoView({ behavior: 'smooth' });
                            }
                        }
                    }
                });
            }
        } catch (error) {
            if (DEBUG) console.log('Cannot access iframe content for navigation handling:', error);
        }
    });
}

/**
 * Display DOCX preview in main content area
 */
async function displayDocxPreview(file, filePath, fileName, fileHandle, lastModified) {
    const contentContainer = document.getElementById('content-container');
    if (!contentContainer) {
        alert('Error: content-container element not found!');
        return;
    }

    document.querySelectorAll('.file-view-container').forEach(container => {
        container.style.display = 'none';
    });

    if (editorInstances.has(filePath)) {
        const existingInstance = editorInstances.get(filePath);
        if (existingInstance.fileViewContainer) {
            existingInstance.fileViewContainer.style.display = 'flex';
        }
        return;
    }

    const fileViewContainer = document.createElement('div');
    fileViewContainer.className = 'file-view-container flex flex-col h-full';

    const fileHeader = document.createElement('div');
    fileHeader.className = 'file-header flex justify-between items-center px-4 py-2 bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-200 font-medium border-b border-gray-200 dark:border-gray-700';

    const fileTitle = document.createElement('span');
    fileTitle.textContent = fileName || 'No file selected';
    fileHeader.appendChild(fileTitle);

    fileViewContainer.appendChild(fileHeader);

    const docxContainer = document.createElement('div');
    docxContainer.className = 'flex-1 overflow-auto p-4';
    docxContainer.innerHTML = '<div style="text-align:center;padding:2rem;color:#666;">Loading preview...</div>';
    fileViewContainer.appendChild(docxContainer);

    contentContainer.appendChild(fileViewContainer);

    const instanceData = {
        fileViewContainer: fileViewContainer,
        fileHandle: fileHandle,
        lastModified: lastModified,
        isDirty: false
    };
    editorInstances.set(filePath, instanceData);

    try {
        // jszip + docx-preview bundled into the dist HTML; window.JSZip
        // and window.docx are available synchronously.
        const arrayBuffer = await file.arrayBuffer();
        docxContainer.innerHTML = '';
        await window.docx.renderAsync(arrayBuffer, docxContainer);
    } catch (err) {
        console.error('Error rendering DOCX:', err);
        docxContainer.innerHTML = `<div style="text-align:center;padding:2rem;color:#c00;">Error rendering DOCX: ${err.message}</div>`;
    }
}

/**
 * Display XLSX/XLS preview in main content area
 */
async function displayXlsxPreview(file, filePath, fileName, fileHandle, lastModified) {
    const contentContainer = document.getElementById('content-container');
    if (!contentContainer) {
        alert('Error: content-container element not found!');
        return;
    }

    document.querySelectorAll('.file-view-container').forEach(container => {
        container.style.display = 'none';
    });

    if (editorInstances.has(filePath)) {
        const existingInstance = editorInstances.get(filePath);
        if (existingInstance.fileViewContainer) {
            existingInstance.fileViewContainer.style.display = 'flex';
        }
        return;
    }

    const fileViewContainer = document.createElement('div');
    fileViewContainer.className = 'file-view-container flex flex-col h-full';

    const fileHeader = document.createElement('div');
    fileHeader.className = 'file-header flex justify-between items-center px-4 py-2 bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-200 font-medium border-b border-gray-200 dark:border-gray-700';

    const fileTitle = document.createElement('span');
    fileTitle.textContent = fileName || 'No file selected';
    fileHeader.appendChild(fileTitle);

    fileViewContainer.appendChild(fileHeader);

    const xlsxContainer = document.createElement('div');
    xlsxContainer.className = 'flex-1 overflow-auto';
    xlsxContainer.innerHTML = '<div style="text-align:center;padding:2rem;color:#666;">Loading preview...</div>';
    fileViewContainer.appendChild(xlsxContainer);

    contentContainer.appendChild(fileViewContainer);

    const instanceData = {
        fileViewContainer: fileViewContainer,
        fileHandle: fileHandle,
        lastModified: lastModified,
        isDirty: false
    };
    editorInstances.set(filePath, instanceData);

    try {
        // XLSX bundled into the dist HTML; window.XLSX is available
        // synchronously, no runtime load needed.
        const arrayBuffer = await file.arrayBuffer();
        const workbook = XLSX.read(arrayBuffer, { type: 'array' });

        xlsxContainer.innerHTML = '';

        if (workbook.SheetNames.length > 1) {
            const tabs = document.createElement('div');
            tabs.style.cssText = 'display:flex;gap:0;border-bottom:1px solid #ddd;background:#f5f5f5;';
            const tableArea = document.createElement('div');
            tableArea.className = 'flex-1 overflow-auto';

            workbook.SheetNames.forEach((name, i) => {
                const tab = document.createElement('button');
                tab.textContent = name;
                tab.style.cssText = 'padding:0.4rem 1rem;cursor:pointer;border:1px solid transparent;border-bottom:none;font-size:0.85rem;background:transparent;';
                if (i === 0) tab.style.cssText += 'background:white;border-color:#ddd;border-bottom-color:white;margin-bottom:-1px;font-weight:500;';
                tab.onclick = () => {
                    tabs.querySelectorAll('button').forEach(t => { t.style.background = 'transparent'; t.style.borderColor = 'transparent'; t.style.fontWeight = 'normal'; });
                    tab.style.cssText = 'padding:0.4rem 1rem;cursor:pointer;border:1px solid #ddd;border-bottom-color:white;font-size:0.85rem;background:white;margin-bottom:-1px;font-weight:500;';
                    renderXlsxSheet(workbook, name, tableArea);
                };
                tabs.appendChild(tab);
            });

            xlsxContainer.appendChild(tabs);
            xlsxContainer.appendChild(tableArea);
            renderXlsxSheet(workbook, workbook.SheetNames[0], tableArea);
        } else {
            renderXlsxSheet(workbook, workbook.SheetNames[0], xlsxContainer);
        }
    } catch (err) {
        console.error('Error rendering XLSX:', err);
        xlsxContainer.innerHTML = `<div style="text-align:center;padding:2rem;color:#c00;">Error rendering spreadsheet: ${err.message}</div>`;
    }
}

/**
 * Render a single XLSX sheet as an HTML table
 */
function renderXlsxSheet(workbook, sheetName, container) {
    const sheet = workbook.Sheets[sheetName];
    const html = XLSX.utils.sheet_to_html(sheet, { editable: false });
    container.innerHTML = html;
    const table = container.querySelector('table');
    if (table) {
        table.style.cssText = 'border-collapse:collapse;width:100%;font-size:0.85rem;';
        table.querySelectorAll('th,td').forEach(cell => {
            cell.style.cssText = 'border:1px solid #ddd;padding:0.35rem 0.5rem;text-align:left;white-space:nowrap;';
        });
        table.querySelectorAll('th').forEach(th => {
            th.style.background = '#f0f0f0';
            th.style.fontWeight = '600';
        });
    }
}

/**
 * Display PDF preview using browser's built-in PDF viewer
 */
async function displayPdfPreview(file, filePath, fileName, fileHandle, lastModified) {
    const contentContainer = document.getElementById('content-container');
    if (!contentContainer) return;

    document.querySelectorAll('.file-view-container').forEach(container => {
        container.style.display = 'none';
    });

    if (editorInstances.has(filePath)) {
        const existingInstance = editorInstances.get(filePath);
        if (existingInstance.fileViewContainer) {
            existingInstance.fileViewContainer.style.display = 'flex';
        }
        return;
    }

    const fileViewContainer = document.createElement('div');
    fileViewContainer.className = 'file-view-container flex flex-col h-full';

    const fileHeader = document.createElement('div');
    fileHeader.className = 'file-header flex justify-between items-center px-4 py-2 bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-200 font-medium border-b border-gray-200 dark:border-gray-700';

    const fileTitle = document.createElement('span');
    fileTitle.textContent = fileName;
    fileHeader.appendChild(fileTitle);
    fileViewContainer.appendChild(fileHeader);

    const pdfContainer = document.createElement('div');
    pdfContainer.className = 'flex-1 overflow-hidden';

    const objectUrl = URL.createObjectURL(file);

    const iframe = document.createElement('iframe');
    iframe.className = 'w-full h-full border-0';
    iframe.src = objectUrl;
    iframe.setAttribute('title', fileName);

    pdfContainer.appendChild(iframe);
    fileViewContainer.appendChild(pdfContainer);
    contentContainer.appendChild(fileViewContainer);

    editorInstances.set(filePath, {
        fileViewContainer,
        fileHandle,
        lastModified,
        isDirty: false,
        objectUrl
    });
}

/**
 * Update status bar counts
 */
function updateStatusCounts(folderCount, fileCount) {
    const folderCountElement = document.getElementById('folder-count');
    const fileCountElement = document.getElementById('file-count');

    if (folderCountElement) {
        folderCountElement.textContent = `${folderCount} folder${folderCount !== 1 ? 's' : ''}`;
    }

    if (fileCountElement) {
        fileCountElement.textContent = `${fileCount} file${fileCount !== 1 ? 's' : ''}`;
    }

    updateUnsavedCount();
}

/**
 * Update unsaved count in status bar
 */
function updateUnsavedCount() {
    const unsavedCountElement = document.getElementById('unsaved-count');
    if (!unsavedCountElement) return;

    let dirtyCount = 0;
    editorInstances.forEach(instance => {
        if (instance.isDirty) {
            dirtyCount++;
        }
    });

    unsavedCountElement.textContent = `${dirtyCount} unsaved`;

    if (dirtyCount > 0) {
        unsavedCountElement.classList.add('text-amber-500', 'font-medium');
    } else {
        unsavedCountElement.classList.remove('text-amber-500', 'font-medium');
    }
}

/**
 * Update file dirty status indicator in tree
 */
function updateFileDirtyStatus(filePath, isDirty) {
    const fileElement = document.querySelector(`.file-item[data-path="${filePath}"]`);
    if (!fileElement) return;

    if (isDirty) {
        if (!fileElement.querySelector('.dirty-indicator')) {
            const indicator = document.createElement('span');
            indicator.className = 'dirty-indicator ml-1 text-amber-500 font-bold';
            indicator.textContent = '●';
            fileElement.appendChild(indicator);
        }
        fileElement.classList.add('is-dirty');
    } else {
        const indicator = fileElement.querySelector('.dirty-indicator');
        if (indicator) {
            fileElement.removeChild(indicator);
        }
        fileElement.classList.remove('is-dirty');
    }
}
