/**
 * ZDDC Classifier - Main Application
 * Spreadsheet-based file renaming with Excel-like formulas
 */
(function() {
    'use strict';

    // Global application state
    window.app = {
        // File System
        rootHandle: null,
        
        // Data
        folderTree: [],
        selectedFolders: new Set(), // Multi-select support
        lastSelectedFolderPath: null,
        hideCompliant: false,
        calculateSha256: false,
        
        // DOM elements (populated on init)
        dom: {},
        
        // Modules (populated by other files)
        modules: {}
    };

    /**
     * Initialize the application
     */
    function init() {
        // Cache DOM elements + wire events first so the welcome screen
        // (and the HTTP-mode auto-load below) can use them.
        cacheDOMElements();
        setupEventListeners();

        // Workspace manager (renders the welcome list, owns new/open/autosave).
        if (app.modules.workspace) app.modules.workspace.init();

        // Browser-compatibility branch:
        //   HTTP mode (served by zddc-server) — works everywhere; the
        //     HTTP polyfill stands in for the FS Access API. Auto-load
        //     the directory the page lives in.
        //   Local mode (file://) — requires FS Access API for write
        //     access to the user-picked folder. Show the warning if
        //     the API is missing.
        if (location.protocol === 'http:' || location.protocol === 'https:') {
            // Don't disable the picker button — even in HTTP mode the
            // user might want to add a local folder. But the auto-load
            // below means the welcome screen usually never shows.
            (async function () {
                try {
                    var probe = await window.zddc.source.detectServerRoot();
                    if (probe.handle) {
                        await openDirectory(probe.handle);
                        return;
                    }
                    if (probe.status === 403) {
                        showHttpForbiddenMessage();
                        return;
                    }
                } catch (err) {
                    console.warn('classifier: server-mode auto-load failed:', err);
                }
                // Server-mode probe inconclusive — fall through to welcome.
                if (!checkBrowserCompatibility()) {
                    showBrowserWarning();
                    return;
                }
                showWelcomeScreen();
            })();
            return;
        }

        if (!checkBrowserCompatibility()) {
            showBrowserWarning();
            return;
        }
        showWelcomeScreen();
    }

    /**
     * Check if browser supports File System Access API. Used in local
     * (file://) mode only — HTTP mode runs through the HTTP polyfill,
     * which has no browser dependency beyond fetch.
     */
    function checkBrowserCompatibility() {
        return 'showDirectoryPicker' in window;
    }

    /**
     * Show a clear "no permission to list" message for HTTP-mode users
     * who land on a path their ACL doesn't allow them to list. Distinct
     * from the welcome screen so the user understands why the file tree
     * is empty rather than wondering if they need to pick a folder.
     */
    function showHttpForbiddenMessage() {
        var screen = document.getElementById('welcomeScreen');
        if (!screen) return;
        screen.classList.remove('hidden');
        var msg = document.createElement('div');
        msg.className = 'classifier-forbidden-message';
        msg.style.cssText = 'padding: 1.5rem; max-width: 36rem; margin: 0 auto; text-align: center;';
        msg.innerHTML =
            '<h2 style="margin-bottom: 0.75rem;">No permission to list this directory</h2>' +
            '<p>Your account does not have read access to this folder. ' +
            'You may still be able to upload files if your role allows it; ' +
            'contact the document controller if you believe this is wrong.</p>';
        screen.appendChild(msg);
        var addBtn = document.getElementById('addDirectoryBtn');
        if (addBtn) addBtn.disabled = true;
    }

    /**
     * Show browser compatibility warning
     */
    function showBrowserWarning() {
        const warning = document.getElementById('browserWarning');
        const selectBtn = document.getElementById('addDirectoryBtn');
        if (warning) {
            warning.classList.remove('hidden');
        }
        if (selectBtn) {
            selectBtn.disabled = true;
            selectBtn.textContent = 'Browser Not Supported';
        }
    }

    /**
     * Cache DOM element references
     */
    function cacheDOMElements() {
        app.dom = {
            // Screens
            welcomeScreen: document.getElementById('welcomeScreen'),
            mainApp: document.getElementById('mainApp'),
            
            // Header buttons
            addDirectoryBtn: document.getElementById('addDirectoryBtn'),
            refreshHeaderBtn: document.getElementById('refreshHeaderBtn'),
            saveAllBtn: document.getElementById('saveAllBtn'),
            cancelAllBtn: document.getElementById('cancelAllBtn'),
            exportHashesBtn: document.getElementById('exportHashesBtn'),
            sha256Checkbox: document.getElementById('sha256Checkbox'),
            hideCompliantCheckbox: document.getElementById('hideCompliantCheckbox'),
            hideCompliantLabel: document.getElementById('hideCompliantLabel'),
            classifyFilters: document.getElementById('classifyFilters'),
            showUnassignedCheckbox: document.getElementById('showUnassignedCheckbox'),
            showAssignedCheckbox: document.getElementById('showAssignedCheckbox'),
            showExcludedCheckbox: document.getElementById('showExcludedCheckbox'),
            showEmptyCheckbox: document.getElementById('showEmptyCheckbox'),
            exportDatasetBtn: document.getElementById('exportDatasetBtn'),
            importDatasetBtn: document.getElementById('importDatasetBtn'),
            importDatasetInput: document.getElementById('importDatasetInput'),
            resetDatasetBtn: document.getElementById('resetDatasetBtn'),
            treeFilterInput: document.getElementById('treeFilterInput'),
            trackingFilterInput: document.getElementById('trackingFilterInput'),
            transmittalFilterInput: document.getElementById('transmittalFilterInput'),

            // Folder tree
            folderTree: document.getElementById('folderTree'),
            folderTreePane: document.getElementById('folderTreePane'),
            collapseTreeBtn: document.getElementById('collapseTreeBtn'),
            autoScrollCheckbox: document.getElementById('autoScrollCheckbox'),
            selectedFoldersCount: document.getElementById('selectedFoldersCount'),
            
            // Spreadsheet
            spreadsheet: document.getElementById('spreadsheet'),
            spreadsheetBody: document.getElementById('spreadsheetBody'),
            sha256Column: document.getElementById('sha256Column'),
            
            // Stats
            totalFiles: document.getElementById('totalFiles'),
            modifiedFiles: document.getElementById('modifiedFiles'),
            errorFiles: document.getElementById('errorFiles'),
            
            // Preview
            togglePreviewBtn: document.getElementById('togglePreviewBtn'),

            // Mode switch + Classify & Copy panes
            modeRenameBtn: document.getElementById('modeRenameBtn'),
            modeClassifyBtn: document.getElementById('modeClassifyBtn'),
            spreadsheetPane: document.getElementById('spreadsheetPane'),
            targetPane: document.getElementById('targetPane'),
            copyOutputBtn: document.getElementById('copyOutputBtn')
        };
    }

    /**
     * Switch between "Rename" (in-place grid) and "Classify & Copy" (map files
     * onto target trees, copy renamed copies out). The source tree (left) stays
     * in both modes; only the right pane swaps.
     */
    function setMode(mode) {
        const classify = mode === 'classify';
        app.dom.modeRenameBtn.classList.toggle('active', !classify);
        app.dom.modeClassifyBtn.classList.toggle('active', classify);
        if (app.dom.spreadsheetPane) app.dom.spreadsheetPane.hidden = classify;
        if (app.dom.targetPane) app.dom.targetPane.hidden = !classify;
        // Mode-specific source-tree filters: "Hide Compliant" is for the rename
        // grid; "Hide Assigned" is for the classify workflow.
        if (app.dom.hideCompliantLabel) app.dom.hideCompliantLabel.hidden = classify;
        if (app.dom.classifyFilters) app.dom.classifyFilters.hidden = !classify;
        app.modules.classify.setEnabled(classify);
        if (classify && app.modules.targetTree) {
            app.modules.targetTree.init();
            app.modules.targetTree.render();
        }
        // Re-render the source tree so its per-file markers appear/disappear.
        if (app.modules.tree) app.modules.tree.render();
    }

    // ── dataset export / import (one record per file) ──────────────────────
    // Round-trip the classification as a flat list of files, each carrying its
    // full ZDDC filename (and optional transmittal). An external editor (e.g. an
    // AI) just sets filenames; on import the app parses each filename and
    // rebuilds the tracking tree (no node ids to manage).
    function eachSourceFile(cb) {
        (function walk(nodes) {
            (nodes || []).forEach(function (n) { (n.files || []).forEach(cb); walk(n.children); });
        })(app.folderTree || []);
    }
    function exportDataset() {
        var c = app.modules.classify, files = [];
        eachSourceFile(function (f) {
            var key = c.srcKeyForFile(f);
            var a = c.getAssignment(key) || {};
            var d = c.deriveTarget(f);
            var rec = {
                source: key,
                originalName: window.zddc.joinExtension(f.originalFilename, f.extension),
                filename: a.excluded ? '' : (d.filename || ''),
                excluded: !!a.excluded,
            };
            if (!a.excluded && a.transmittalNodeId) {
                var t = c.transmittalRecord(a.transmittalNodeId);
                if (t) rec.transmittal = t;
            }
            files.push(rec);
        });
        var payload = {
            zddcClassifierFiles: 1,
            exportedAt: new Date().toISOString(),
            _format: 'One record per input file. Set "filename" to its full ZDDC name '
                + '"TRACKING_REV (STATUS) - Title.ext" — on import the app splits TRACKING on "-" and the '
                + 'final "_" into nested folders, and files in shared paths share ancestors. Set '
                + '"excluded": true for non-documents (filename then ignored). "transmittal" is optional: '
                + '{party, slot:"received"|"issued", date:"YYYY-MM-DD", type:"TRN"|"SUB", seq, status, title}. '
                + 'Classify every "source" key; do not invent files.',
            outputName: c.serialize().outputName || null,
            files: files,
        };
        var name = 'classifier-dataset';
        try {
            if (app.modules.workspace && typeof app.modules.workspace.activeName === 'function') {
                name = app.modules.workspace.activeName() || name;
            }
        } catch (_) { /* ok */ }
        var blob = new Blob([JSON.stringify(payload, null, 2)], { type: 'application/json' });
        var url = URL.createObjectURL(blob);
        var a = document.createElement('a');
        a.href = url;
        a.download = String(name).replace(/[^\w.-]+/g, '_') + '.zddc-classification.json';
        document.body.appendChild(a); a.click(); a.remove();
        URL.revokeObjectURL(url);
    }
    function importDataset(file) {
        var reader = new FileReader();
        reader.onload = function () {
            var obj;
            try { obj = JSON.parse(reader.result); }
            catch (e) { window.zddc.toast('Import failed — not valid JSON.', 'error'); return; }
            if (!obj || !Array.isArray(obj.files)) {
                window.zddc.toast('Import failed — expected a classifier dataset with a "files" list.', 'error'); return;
            }
            var c = app.modules.classify;
            var hasData = c.getTrackingTree().length || c.getTransmittalTree().length
                || Object.keys(c.serialize().assignments || {}).length;
            if (hasData && !confirm('Replace the current classification with the imported dataset?')) return;
            c.reset();
            var ok = 0, bad = 0;
            obj.files.forEach(function (rec) {
                if (!rec || !rec.source) return;
                var key = rec.source;
                if (rec.excluded) { c.setExcluded([key], true); ok++; return; }
                if (rec.filename) {
                    var p = window.zddc.parseFilename(String(rec.filename).trim());
                    if (p && p.valid) {
                        var stem = p.trackingNumber + '_' + p.revision + ' (' + p.status + ')';
                        c.place([key], c.addTrackingPath(null, c.parseFolderLevels(stem)), 'tracking');
                        if (p.title != null) c.setTitleOverride(key, p.title);
                        ok++;
                    } else { bad++; }
                }
                if (rec.transmittal && rec.transmittal.party) {
                    var t = rec.transmittal;
                    var pid = c.findOrAddParty(t.party);
                    var bid = c.findOrAddTransmittalBin(pid, t.slot || 'received', {
                        date: t.date, type: t.type || 'TRN', seq: t.seq, status: t.status, title: t.title,
                    });
                    if (bid) c.place([key], bid, 'transmittal');
                }
            });
            window.zddc.toast('Imported ' + ok + ' file' + (ok === 1 ? '' : 's')
                + (bad ? (' — ' + bad + ' had an unparseable filename') : '') + '.', bad ? 'warning' : 'success');
        };
        reader.onerror = function () { window.zddc.toast('Import failed — could not read the file.', 'error'); };
        reader.readAsText(file);
    }
    // Reset to a clean state: keep the scanned source tree (the raw input), but
    // discard every classification — trees, assignments, excludes, overrides.
    // Destructive and irreversible, so warn and steer the user to Export first.
    function resetDataset() {
        var c = app.modules.classify;
        var n = Object.keys(c.serialize().assignments || {}).length;
        if (!n && !c.getTrackingTree().length && !c.getTransmittalTree().length) {
            window.zddc.toast('Nothing to reset — already at the raw input.', 'info');
            return;
        }
        if (!confirm('Reset to a clean state?\n\nThis discards ALL classifications ('
            + n + ' assigned file' + (n === 1 ? '' : 's') + ', plus the tracking and '
            + 'transmittal trees) and returns to just the raw scanned input. Your actual '
            + 'files are not touched.\n\nThis cannot be undone — Export first if you might '
            + 'need this data.')) return;
        c.reset();
        window.zddc.toast('Reset to the raw scanned input.', 'success');
    }

    /**
     * Set up event listeners
     */
    function setupEventListeners() {
        // Directory selection
        app.dom.addDirectoryBtn.addEventListener('click', handleSelectDirectory);
        app.dom.refreshHeaderBtn.addEventListener('click', handleRefresh);
        
        // Drag and drop on welcome screen
        setupWelcomeDragDrop();
        
        // Bulk actions
        app.dom.saveAllBtn.addEventListener('click', handleSaveAll);
        app.dom.cancelAllBtn.addEventListener('click', handleCancelAll);
        
        // Export hashes
        app.dom.exportHashesBtn.addEventListener('click', handleExportHashes);
        
        // SHA256 toggle
        app.dom.sha256Checkbox.addEventListener('change', handleSha256Toggle);
        
        // Hide compliant toggle
        app.dom.hideCompliantCheckbox.addEventListener('change', handleHideCompliantToggle);

        // Classify-mode source-tree filters: show/hide unassigned, assigned, excluded.
        function pushClassifyFilters() {
            if (app.modules.tree && app.modules.tree.setShowFilters) {
                app.modules.tree.setShowFilters({
                    unassigned: app.dom.showUnassignedCheckbox.checked,
                    assigned: app.dom.showAssignedCheckbox.checked,
                    excluded: app.dom.showExcludedCheckbox.checked,
                    empty: app.dom.showEmptyCheckbox.checked,
                });
            }
        }
        [app.dom.showUnassignedCheckbox, app.dom.showAssignedCheckbox, app.dom.showExcludedCheckbox, app.dom.showEmptyCheckbox]
            .forEach(function (cb) { if (cb) cb.addEventListener('change', pushClassifyFilters); });

        // Collapse tree button
        app.dom.collapseTreeBtn.addEventListener('click', handleCollapseTree);

        // Workflow mode switch
        if (app.dom.modeRenameBtn) app.dom.modeRenameBtn.addEventListener('click', function () { setMode('rename'); });
        if (app.dom.modeClassifyBtn) app.dom.modeClassifyBtn.addEventListener('click', function () { setMode('classify'); });
        if (app.dom.copyOutputBtn) app.dom.copyOutputBtn.addEventListener('click', function () { app.modules.copy.run(); });

        // Live source-tree filter (matches file path + name; reveals the hierarchy).
        if (app.dom.treeFilterInput) app.dom.treeFilterInput.addEventListener('input', function () {
            if (app.modules.tree && app.modules.tree.setNameFilter) app.modules.tree.setNameFilter(this.value);
        });
        // Target-tree filter — both tabs share one query (mirrored across inputs).
        function targetFilter(val) {
            if (app.dom.trackingFilterInput) app.dom.trackingFilterInput.value = val;
            if (app.dom.transmittalFilterInput) app.dom.transmittalFilterInput.value = val;
            if (app.modules.targetTree && app.modules.targetTree.setNameFilter) app.modules.targetTree.setNameFilter(val);
        }
        [app.dom.trackingFilterInput, app.dom.transmittalFilterInput].forEach(function (inp) {
            if (inp) inp.addEventListener('input', function () { targetFilter(this.value); });
        });

        // Dataset export / import (round-trip the classification through a JSON file).
        if (app.dom.exportDatasetBtn) app.dom.exportDatasetBtn.addEventListener('click', exportDataset);
        if (app.dom.importDatasetBtn) app.dom.importDatasetBtn.addEventListener('click', function () { app.dom.importDatasetInput.click(); });
        if (app.dom.resetDatasetBtn) app.dom.resetDatasetBtn.addEventListener('click', resetDataset);
        if (app.dom.importDatasetInput) app.dom.importDatasetInput.addEventListener('change', function () {
            if (this.files && this.files[0]) importDataset(this.files[0]);
            this.value = '';   // allow re-importing the same file
        });
        
        // Keyboard shortcuts
        document.addEventListener('keydown', handleKeyDown);
        
        // Resize handle
        setupResizeHandle();

        // Re-render the source tree when classify state changes (so file dots
        // and placements stay in sync after a drop). Cheap no-op outside
        // classify mode.
        if (app.modules.classify) {
            app.modules.classify.on(function () {
                if (app.modules.classify.isEnabled() && app.modules.tree) app.modules.tree.render();
            });
        }
    }
    
    /**
     * Handle collapse/expand folder tree pane
     */
    function handleCollapseTree() {
        const pane = app.dom.folderTreePane;
        const btn = app.dom.collapseTreeBtn;
        
        pane.classList.toggle('collapsed');
        
        if (pane.classList.contains('collapsed')) {
            // Clear any inline width from resize handle
            pane.style.width = '';
            btn.textContent = '▶';
            btn.title = 'Expand folder tree';
        } else {
            btn.textContent = '◀';
            btn.title = 'Collapse folder tree';
        }
    }

    /**
     * Set up folder tree resize handle
     */
    function setupResizeHandle() {
        const handle = document.getElementById('treeResizeHandle');
        const pane = document.getElementById('folderTreePane');
        
        if (!handle || !pane) return;
        
        let isResizing = false;
        let startX = 0;
        let startWidth = 0;
        
        handle.addEventListener('mousedown', (e) => {
            isResizing = true;
            startX = e.clientX;
            startWidth = pane.offsetWidth;
            document.body.style.cursor = 'col-resize';
            e.preventDefault();
        });
        
        document.addEventListener('mousemove', (e) => {
            if (!isResizing) return;
            
            const delta = e.clientX - startX;
            const newWidth = startWidth + delta;
            
            // Respect min width only
            if (newWidth >= 150) {
                pane.style.width = newWidth + 'px';
            }
        });
        
        document.addEventListener('mouseup', () => {
            if (isResizing) {
                isResizing = false;
                document.body.style.cursor = '';
            }
        });
    }

    /**
     * Set up drag-and-drop on the welcome screen
     */
    function setupWelcomeDragDrop() {
        const screen = app.dom.welcomeScreen;
        if (!screen) return;
        
        ['dragenter', 'dragover'].forEach(evt => {
            screen.addEventListener(evt, (e) => {
                e.preventDefault();
                screen.classList.add('drag-over');
            });
        });
        
        ['dragleave', 'drop'].forEach(evt => {
            screen.addEventListener(evt, (e) => {
                e.preventDefault();
                screen.classList.remove('drag-over');
            });
        });
        
        screen.addEventListener('drop', async (e) => {
            const item = e.dataTransfer.items && e.dataTransfer.items[0];
            if (!item) return;
            
            const handle = await item.getAsFileSystemHandle();
            if (!handle || handle.kind !== 'directory') {
                alert('Please drop a folder, not a file.');
                return;
            }
            
            await openDirectory(handle);
        });
    }

    /**
     * Handle directory selection via button click
     */
    async function handleSelectDirectory() {
        try {
            const dirHandle = await window.showDirectoryPicker();
            await openDirectory(dirHandle);
        } catch (err) {
            if (err.name !== 'AbortError') {
                console.error('Error selecting directory:', err);
                alert('Error selecting directory: ' + err.message);
            }
        }
    }

    /**
     * Open a directory handle and initialize the application
     */
    // Show the main UI and initialize the per-tool modules ONCE. Shared by the
    // legacy rename open and the workspace open/new flows (the latter scan or
    // load a snapshot themselves).
    var shellInited = false;
    function enterAppShell() {
        hideWelcomeScreen();
        showMainUI();
        if (!shellInited) {
            shellInited = true;
            app.modules.spreadsheet.init();  // Subscribe to store
            app.modules.selection.init();
            app.modules.preview.init();      // After selection so it can listen for rowfocused
            app.modules.resize.init();
            app.modules.filter.init();
            app.modules.sort.init();
            app.modules.tree.setupKeyboardShortcuts();
            if (app.modules.targetTree) app.modules.targetTree.init();
        }
        if (app.dom.refreshHeaderBtn) app.dom.refreshHeaderBtn.classList.remove('hidden');
    }

    async function openDirectory(dirHandle) {
        app.rootHandle = dirHandle;
        enterAppShell();
        // Default to Classify & Copy (the primary workflow). The user can switch
        // to "Rename in place" via the toggle for the spreadsheet.
        setMode('classify');
        // Now scan directory (this will trigger store updates and renders)
        await app.modules.scanner.scanDirectory(dirHandle);
    }

    /**
     * Handle Refresh button - rescan current directory
     */
    async function handleRefresh() {
        if (!app.rootHandle) {
            alert('No directory selected');
            return;
        }

        try {
            // A snapshot-loaded workspace handle needs its read permission
            // re-granted before we can enumerate it again.
            if (app.modules.persist && app.modules.persist.verifyPermission) {
                const ok = await app.modules.persist.verifyPermission(app.rootHandle, false);
                if (!ok) {
                    if (window.zddc) window.zddc.toast('Permission to read the source directory was denied.', 'error');
                    return;
                }
            }

            // Clear current data
            app.folderTree = [];
            app.selectedFolders.clear();
            app.lastSelectedFolderPath = null;

            // Reset store
            app.modules.store.reset();

            // Rescan directory (modules already initialized, just rescan)
            await app.modules.scanner.scanDirectory(app.rootHandle);

            // For a workspace, persist the refreshed snapshot (additive: the
            // path-keyed map re-attaches; new files appear unassigned).
            if (app.modules.workspace && app.modules.workspace.onRescanned) {
                app.modules.workspace.onRescanned();
            }

        } catch (err) {
            console.error('Error refreshing directory:', err);
            alert('Error refreshing directory: ' + err.message);
        }
    }

    /**
     * Handle Save All button
     */
    async function handleSaveAll() {
        if (!confirm('Save all modified files?')) return;
        
        try {
            app.dom.saveAllBtn.disabled = true;
            await app.modules.spreadsheet.saveAllFiles();
        } catch (err) {
            console.error('Error saving files:', err);
            alert('Error saving files: ' + err.message);
        } finally {
            app.dom.saveAllBtn.disabled = false;
        }
    }

    /**
     * Handle Cancel All button
     */
    function handleCancelAll() {
        if (!confirm('Cancel all changes?')) return;
        app.modules.spreadsheet.cancelAllChanges();
    }

    /**
     * Handle Export Hashes button
     */
    function handleExportHashes() {
        app.modules.excel.exportHashes();
    }

    /**
     * Handle SHA256 checkbox toggle
     */
    function handleSha256Toggle() {
        app.calculateSha256 = app.dom.sha256Checkbox.checked;
        
        // Show/hide SHA256 column
        if (app.calculateSha256) {
            app.dom.sha256Column.classList.remove('hidden');
        } else {
            app.dom.sha256Column.classList.add('hidden');
        }
        
        // Re-render table
        app.modules.spreadsheet.render();
    }

    /**
     * Handle Hide Compliant checkbox toggle
     */
    function handleHideCompliantToggle() {
        app.hideCompliant = app.dom.hideCompliantCheckbox.checked;
        app.modules.store.setHideCompliant(app.hideCompliant);
    }

    /**
     * Handle keyboard shortcuts
     */
    function handleKeyDown(e) {
        // Ctrl+S - Save All
        if (e.ctrlKey && e.key === 's') {
            e.preventDefault();
            if (!app.dom.saveAllBtn.disabled) {
                handleSaveAll();
            }
        }
        
        // Escape - Cancel editing
        if (e.key === 'Escape') {
            app.modules.spreadsheet.cancelEditing();
        }
    }

    /**
     * Show welcome screen (empty-state overlay)
     */
    function showWelcomeScreen() {
        if (app.dom.welcomeScreen) {
            app.dom.welcomeScreen.classList.remove('hidden');
        }
    }

    /**
     * Hide welcome screen (empty-state overlay)
     */
    function hideWelcomeScreen() {
        if (app.dom.welcomeScreen) {
            app.dom.welcomeScreen.classList.add('hidden');
        }
    }

    /**
     * Show main UI (no-op: main UI is always rendered)
     */
    function showMainUI() {
        // Main app is always visible; only the empty-state overlay is toggled
    }

    /**
     * Update stats display
     */
    function updateStats() {
        const files = app.modules.store.getDisplayFiles();
        const totalFiles = files.length;
        const modifiedFiles = files.filter(f => f.isDirty).length;
        const errorFiles = files.filter(f => f.error).length;
        
        app.dom.totalFiles.textContent = `${totalFiles} file${totalFiles !== 1 ? 's' : ''}`;
        app.dom.modifiedFiles.textContent = `${modifiedFiles} modified`;
        
        if (errorFiles > 0) {
            app.dom.errorFiles.textContent = `${errorFiles} error${errorFiles !== 1 ? 's' : ''}`;
            app.dom.errorFiles.classList.remove('hidden');
        } else {
            app.dom.errorFiles.classList.add('hidden');
        }
        
        // Enable/disable bulk action buttons
        app.dom.saveAllBtn.disabled = modifiedFiles === 0;
        app.dom.cancelAllBtn.disabled = modifiedFiles === 0;
        
        // Enable/disable export hashes button
        app.dom.exportHashesBtn.disabled = totalFiles === 0 || !app.calculateSha256;
    }

    // Export functions for use by other modules
    app.modules.app = {
        updateStats,
        setMode,
        enterAppShell
    };

    // Initialize when DOM is ready
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();
