/**
 * File system operations using File System Access API
 */

/**
 * Open the scratchpad editor
 */
function openScratchpad() {
    // Check if scratchpad already exists
    if (editorInstances.has(SCRATCHPAD_ID)) {
        // Just show it
        const instance = editorInstances.get(SCRATCHPAD_ID);
        document.getElementById('welcome-screen').classList.add('hidden');
        document.getElementById('content-container').classList.remove('hidden');
        
        // Hide all other editors, show scratchpad
        editorInstances.forEach((data, path) => {
            if (data.fileViewContainer) {
                data.fileViewContainer.style.display = path === SCRATCHPAD_ID ? 'flex' : 'none';
            }
        });
        return;
    }
    
    // Hide welcome screen, show content container
    document.getElementById('welcome-screen').classList.add('hidden');
    document.getElementById('content-container').classList.remove('hidden');

    // Initialize editor with the welcome text seeded as the starting content.
    initializeEditor(SCRATCHPAD_WELCOME, true, SCRATCHPAD_ID, 'Scratchpad', null, null);

    // Mark as scratchpad
    const instance = editorInstances.get(SCRATCHPAD_ID);
    if (instance) {
        instance.isScratchpad = true;
    }

    // Reflect non-empty starting content on the scratchpad row's download button.
    updateScratchpadDownloadState();

    if (DEBUG) console.log('Opened scratchpad');
}

/**
 * Enable/disable the scratchpad-row download button based on whether the
 * scratchpad currently holds any content. Idempotent — safe to call from
 * editor change listeners.
 */
function updateScratchpadDownloadState() {
    const btn = document.getElementById('scratchpad-download-btn');
    if (!btn) return;
    const instance = editorInstances.get(SCRATCHPAD_ID);
    let hasContent = false;
    if (instance && instance.editor) {
        try {
            hasContent = (instance.editor.getMarkdown() || '').trim().length > 0;
        } catch (_) { /* editor may not be ready yet */ }
    }
    btn.disabled = !hasContent;
    btn.classList.toggle('is-disabled', !hasContent);
}

/**
 * Trigger a browser download of the current scratchpad markdown.
 * No-op if the scratchpad has no content.
 */
function downloadScratchpad() {
    const instance = editorInstances.get(SCRATCHPAD_ID);
    if (!instance || !instance.editor) return;
    let content = '';
    try { content = instance.editor.getMarkdown() || ''; } catch (_) { return; }

    // Pull front matter from the textarea if any
    if (instance.frontMatterTextarea) {
        const fmText = instance.frontMatterTextarea.value.trim();
        if (fmText) content = `---\n${fmText}\n---\n${content}`;
    }

    if (!content.trim()) return;

    // Suggest a filename derived from the first H1 if present
    let suggested = 'scratchpad.md';
    const h1 = content.match(/^#\s+(.+)$/m);
    if (h1) {
        const slug = h1[1].trim().toLowerCase()
            .replace(/[^a-z0-9\s-]/g, '')
            .replace(/\s+/g, '-')
            .substring(0, 60);
        if (slug) suggested = `${slug}.md`;
    }

    saveFileAs(content, suggested);
}

/**
 * Save file using Save As dialog (for scratchpads or new saves)
 * @param {string} content - Content to save
 * @param {string} suggestedName - Suggested filename
 * @returns {Promise<FileSystemFileHandle|null>} File handle if saved, null otherwise
 */
async function saveFileAs(content, suggestedName = 'untitled.md') {
    if (hasFileSystemAccess) {
        try {
            const fileHandle = await window.showSaveFilePicker({
                suggestedName: suggestedName,
                types: [{
                    description: 'Markdown files',
                    accept: { 'text/markdown': ['.md', '.markdown'] }
                }]
            });
            
            const writable = await fileHandle.createWritable();
            await writable.write(content);
            await writable.close();
            
            if (DEBUG) console.log(`File saved as: ${fileHandle.name}`);
            return fileHandle;
        } catch (error) {
            if (error.name === 'AbortError') {
                if (DEBUG) console.log('Save cancelled by user');
                return null;
            }
            throw error;
        }
    } else {
        // Fallback: download as blob
        const blob = new Blob([content], { type: 'text/markdown' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = suggestedName;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);
        if (DEBUG) console.log(`File downloaded as: ${suggestedName}`);
        return null;
    }
}

/**
 * Open directory picker and handle selection
 */
async function openDirectory() {
    try {
        if (!('showDirectoryPicker' in window)) {
            throw new Error('The File System API is not supported in this browser.');
        }

        directoryHandle = await window.showDirectoryPicker();
        if (DEBUG) console.log('Directory selected:', directoryHandle.name);

        // Local picker wins over any active server-source mode.
        serverSourceMode = false;

        updateDirectoryStatus(directoryHandle.name);
        await readDirectory(directoryHandle);

    } catch (error) {
        if (error.name === 'AbortError') {
            if (DEBUG) console.log('User cancelled the directory selection');
        } else {
            console.error('Error selecting directory:', error);
            alert(`Error: ${error.message}`);
        }
    }
}

/**
 * Update UI to show selected directory
 * @param {string} directoryName - Name of the selected directory
 */
function updateDirectoryStatus(directoryName) {
    // Standardized header pattern (across all ZDDC tools): the button
    // keeps the label "Add Local Directory"; de-emphasize it once a
    // directory is loaded (the user can still click to pick another)
    // by applying the shared btn--subtle variant. The directory name
    // is shown in the file-nav pane, not on the button.
    const selectDirectoryBtn = document.getElementById('addDirectoryBtn');
    if (selectDirectoryBtn) {
        selectDirectoryBtn.classList.remove('btn-primary');
        selectDirectoryBtn.classList.add('btn--subtle');
        selectDirectoryBtn.title = `Loaded: ${directoryName} — click to switch`;
    }

    const refreshBtn = document.getElementById('refreshHeaderBtn');
    if (refreshBtn) {
        refreshBtn.classList.remove('hidden');
    }

    // Show new file button when directory is selected
    const newFileRootBtn = document.getElementById('new-file-root');
    if (newFileRootBtn) {
        newFileRootBtn.classList.remove('hidden');
    }
}

/**
 * Read directory contents and build tree structure
 * @param {FileSystemDirectoryHandle} dirHandle - Directory handle
 * @param {Object} parentNode - Parent node in tree (for recursion)
 * @returns {Object} Statistics about the directory
 */
async function readDirectory(dirHandle, parentNode = null) {
    if (parentNode === null) {
        fileTree = {
            name: dirHandle.name,
            type: 'directory',
            handle: dirHandle,
            entries: {}
        };

        const fileTreeElement = document.getElementById('file-tree');
        if (fileTreeElement) {
            fileTreeElement.innerHTML = '';
        }

        parentNode = fileTree;
    }

    try {
        let stats = { folderCount: 0, fileCount: 0 };

        for await (const entry of dirHandle.values()) {
            if (entry.kind === 'file' && !entry.name.startsWith('_')) {
                parentNode.entries[entry.name] = {
                    name: entry.name,
                    type: 'file',
                    handle: entry
                };
                stats.fileCount++;
            } else if (entry.kind === 'directory' && !entry.name.startsWith('_')) {
                const dirNode = {
                    name: entry.name,
                    type: 'directory',
                    handle: entry,
                    entries: {}
                };

                parentNode.entries[entry.name] = dirNode;

                const subStats = await readDirectory(entry, dirNode);
                stats.folderCount += subStats.folderCount + 1;
                stats.fileCount += subStats.fileCount;
            }
        }

        if (parentNode === fileTree) {
            renderFileTree();
            updateStatusCounts(stats.folderCount, stats.fileCount);
        }

        return stats;
    } catch (error) {
        console.error('Error reading directory:', error);
        return { folderCount: 0, fileCount: 0 };
    }
}

/**
 * Save a file by its path
 * @param {string} filePath - Path of the file to save
 * @returns {Promise<boolean>} Whether save was successful
 */
async function saveFile(filePath) {
    if (!filePath && currentFileHandle) {
        filePath = currentFileHandle.name;
    } else if (!filePath) {
        alert('No file is currently open');
        return false;
    }

    try {
        const editorInstance = editorInstances.get(filePath);
        if (!editorInstance) {
            throw new Error('No editor instance found for this file');
        }

        if (!editorInstance.isDirty) {
            if (DEBUG) console.log(`File ${filePath} is not dirty, skipping save`);
            return true;
        }

        const fileHandle = editorInstance.fileHandle;
        if (!fileHandle) {
            throw new Error('No file handle available for this file');
        }

        // Check for external modifications
        const file = await fileHandle.getFile();
        const currentLastModified = file.lastModified;
        const storedLastModified = editorInstance.lastModified;

        if (storedLastModified && currentLastModified !== storedLastModified) {
            const confirmSave = confirm(
                'Warning: This file has been modified outside of the application since you opened it. ' +
                'Saving will overwrite those changes. Do you want to continue?'
            );

            if (!confirmSave) {
                if (DEBUG) console.log('Save aborted by user due to external file modifications');
                return false;
            }
        }

        // Get markdown content from editor
        const markdownContent = editorInstance.editor.getMarkdown();
        
        // Get front matter from textarea
        let frontMatterData = {};
        if (editorInstance.frontMatterTextarea) {
            const frontMatterText = editorInstance.frontMatterTextarea.value.trim();
            if (frontMatterText) {
                try {
                    const yamlContent = `---\n${frontMatterText}\n---\n`;
                    const parsed = parseFrontMatter(yamlContent);
                    frontMatterData = parsed.data;
                } catch (error) {
                    console.error('Error parsing front matter:', error);
                    throw new Error(`Invalid YAML front matter: ${error.message}`);
                }
            }
        }

        // Apply before save hooks
        frontMatterData = await applyBeforeSaveHooks(frontMatterData, markdownContent, fileHandle);

        // Combine front matter with markdown
        const finalContent = frontMatterData && Object.keys(frontMatterData).length > 0
            ? stringifyFrontMatter(markdownContent, frontMatterData)
            : markdownContent;

        // Server-mode files are read-only: fall back to a Save-As download.
        if (typeof fileHandle.createWritable !== 'function') {
            const downloadName = (fileHandle.name || filePath.split('/').pop() || 'untitled.md');
            await saveFileAs(finalContent, downloadName);
            editorInstance.isDirty = false;
            updateFileDirtyStatus(filePath, false);
            updateUnsavedCount();
            if (editorInstance.saveButton) editorInstance.saveButton.disabled = true;
            return true;
        }

        // Write to file
        const writable = await fileHandle.createWritable();
        await writable.write(finalContent);
        await writable.close();

        // Update state
        const updatedFile = await fileHandle.getFile();
        editorInstance.lastModified = updatedFile.lastModified;
        editorInstance.isDirty = false;
        updateFileDirtyStatus(filePath, false);
        updateUnsavedCount();

        if (editorInstance.saveButton) {
            editorInstance.saveButton.disabled = true;
        }

        if (DEBUG) console.log(`File ${filePath} saved successfully!`);
        
        await applyAfterSaveHooks(frontMatterData, markdownContent, fileHandle);
        
        return true;
    } catch (error) {
        console.error(`Error saving file ${filePath}:`, error);
        alert(`Error saving file: ${error.message}`);
        return false;
    }
}

/**
 * Save all files with unsaved changes
 * @returns {Promise<{saved: number, failed: number}>}
 */
async function saveAllFiles() {
    let saved = 0;
    let failed = 0;

    const dirtyFiles = [];
    editorInstances.forEach((instance, filePath) => {
        if (instance.isDirty) {
            dirtyFiles.push(filePath);
        }
    });

    if (dirtyFiles.length === 0) {
        if (DEBUG) console.log('No files with unsaved changes');
        return { saved, failed };
    }

    for (const filePath of dirtyFiles) {
        try {
            const success = await saveFile(filePath);
            if (success) {
                saved++;
            } else {
                failed++;
            }
        } catch (error) {
            console.error(`Error saving file ${filePath}:`, error);
            failed++;
        }
    }

    if (failed === 0) {
        if (DEBUG) console.log(`All ${saved} files saved successfully`);
    } else {
        if (DEBUG) console.log(`Saved ${saved} files, ${failed} files failed to save`);
    }

    return { saved, failed };
}

/**
 * Reload file from disk
 * @param {string} filePath - Path of file to reload
 * @returns {Promise<boolean>} Whether reload was successful
 */
async function reloadFileFromDisk(filePath) {
    try {
        const editorInstance = editorInstances.get(filePath);
        if (!editorInstance) {
            throw new Error('No editor instance found for this file');
        }

        if (editorInstance.isDirty) {
            const confirmReload = confirm(
                'This file has unsaved changes. Reloading will discard all changes. ' +
                'Do you want to continue?'
            );
            
            if (!confirmReload) {
                if (DEBUG) console.log('Reload cancelled by user');
                return false;
            }
        }

        const fileHandle = editorInstance.fileHandle;
        if (!fileHandle) {
            throw new Error('No file handle available for this file');
        }

        const file = await fileHandle.getFile();
        const fileContent = await file.text();
        
        editorInstance.lastModified = file.lastModified;

        if (filePath.endsWith('.md') || filePath.endsWith('.markdown')) {
            const parsed = parseFrontMatter(fileContent);
            
            if (editorInstance.frontMatterTextarea) {
                const frontMatterYaml = stringifyFrontMatterToTextarea(parsed.data);
                editorInstance.frontMatterTextarea.value = frontMatterYaml;
            }
            
            let currentScrollTop = 0;
            try {
                currentScrollTop = editorInstance.editor.getScrollTop();
            } catch (error) {
                if (DEBUG) console.debug('Could not get scroll position:', error);
            }

            editorInstance.editor.setMarkdown(parsed.content);

            setTimeout(() => {
                try {
                    editorInstance.editor.setScrollTop(currentScrollTop);
                } catch (error) {
                    if (DEBUG) console.debug('Could not restore scroll position:', error);
                }
            }, 100);
            
            if (editorInstance.tocContainer) {
                try {
                    updateToc(parsed.content, editorInstance.tocContainer, editorInstance.editor, tocMaxDepth);
                } catch (error) {
                    console.error('Error updating TOC during reload:', error);
                }
            }
        } else {
            editorInstance.editor.setMarkdown(fileContent);
        }

        editorInstance.isDirty = false;
        updateFileDirtyStatus(filePath, false);
        updateUnsavedCount();

        if (editorInstance.saveButton) {
            editorInstance.saveButton.disabled = true;
        }

        if (DEBUG) console.log(`File ${filePath} reloaded successfully from disk!`);
        return true;
    } catch (error) {
        console.error(`Error reloading file ${filePath}:`, error);
        alert(`Error reloading file: ${error.message}`);
        return false;
    }
}

/**
 * Before save hook - apply modifications before saving
 */
async function applyBeforeSaveHooks(frontMatter, markdownContent, fileHandle) {
    frontMatter.lastModified = new Date().toISOString();
    
    if (!frontMatter.title) {
        const firstHeading = markdownContent.match(/^#\s+(.+)$/m);
        if (firstHeading) {
            frontMatter.title = firstHeading[1];
        }
    }
    
    const customTags = (markdownContent.match(/<(deliverable|meeting|report|trkno)>/g) || []).length;
    if (customTags > 0) {
        frontMatter.customTagCount = customTags;
    }
    
    return frontMatter;
}

/**
 * After save hook - perform actions after saving
 */
async function applyAfterSaveHooks(frontMatter, markdownContent, fileHandle) {
    const tags = ['deliverable', 'meeting', 'report', 'trkno'];
    const preservedTags = tags.filter(tag => markdownContent.includes(`<${tag}>`));
    if (preservedTags.length > 0) {
        if (DEBUG) console.log(`Preserved custom tags: ${preservedTags.join(', ')}`);
    }
}

/**
 * Refresh directory from disk without losing unsaved work
 */
async function refreshDirectory() {
    if (serverSourceMode) {
        await loadServerDirectory();
        return;
    }
    if (!directoryHandle) {
        if (DEBUG) console.log('No directory selected, cannot refresh');
        return;
    }

    // Get active file path from DOM before refresh
    const activeFileEl = document.querySelector('.file-item.active-file');
    const activeFilePath = activeFileEl ? activeFileEl.dataset.path : null;

    // Get dirty files from editorInstances
    const dirtyFiles = new Set();
    editorInstances.forEach((instance, filePath) => {
        if (instance.isDirty) {
            dirtyFiles.add(filePath);
        }
    });

    // Re-read directory (calls renderFileTree at the end)
    await readDirectory(directoryHandle);

    // Restore active file state
    if (activeFilePath) {
        const activeElement = document.querySelector(`.file-item[data-path="${activeFilePath}"]`);
        if (activeElement) {
            activeElement.classList.add('active-file');
        }
    }

    // Restore dirty indicators
    dirtyFiles.forEach(filePath => {
        updateFileDirtyStatus(filePath, true);
    });
}

/**
 * Surface a clear "no permission to list this directory" message in
 * the file tree pane when the server returns 403 on the initial
 * listing. Distinct from "host doesn't serve JSON" so the user
 * understands why the tree is empty.
 */
function showServerForbiddenMessage() {
    const treeEl = document.getElementById('file-tree');
    if (!treeEl) return;
    treeEl.innerHTML =
        '<div class="server-forbidden-message" style="padding: 1rem; color: var(--text-muted, #555); font-size: 0.875rem;">' +
        '<strong>No permission to list this directory.</strong>' +
        '<p style="margin: 0.5rem 0 0;">Your account does not have read access here. ' +
        'Contact the document controller if you believe this is wrong.</p>' +
        '</div>';
}

/**
 * Build a CRUD-capable file handle backed by a URL — uses the shared
 * HTTP polyfill from window.zddc.source. The polyfill's getFile() does
 * a GET, and createWritable() PUTs bytes back (file API on zddc-server).
 *
 * Adds `_serverUrl` for legacy code paths that still expect that field.
 * Marks `_readOnly: false` so editor.js leaves save buttons enabled.
 */
function createServerFileHandle(name, url) {
    const handle = new window.zddc.source.HttpFileHandle(url, name);
    handle._serverUrl = url;
    handle._readOnly = false;
    return handle;
}

/**
 * Build a CRUD-capable directory handle backed by a server URL — uses
 * the shared HTTP polyfill. Supports values()/entries(), getFileHandle,
 * getDirectoryHandle({create}), and removeEntry() against the server
 * file API. _serverUrl/_readOnly are kept for legacy probes.
 */
function createServerDirectoryHandle(name, url) {
    const handle = new window.zddc.source.HttpDirectoryHandle(url, name);
    handle._serverUrl = url;
    handle._readOnly = false;
    return handle;
}

/**
 * Recursively fetch the JSON directory listing for `dirUrl` and populate
 * `parentNode.entries` with synthetic handles. Returns folder/file counts.
 * Uses the same Caddy/zddc-server JSON shape archive's source.js consumes.
 */
async function readServerDirectory(dirUrl, parentNode, depth) {
    if (depth > 10) return { folderCount: 0, fileCount: 0 };

    let items;
    try {
        const resp = await fetch(dirUrl, { headers: { 'Accept': 'application/json' }, cache: 'no-cache' });
        if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
        items = await resp.json();
        if (!Array.isArray(items)) throw new Error('Expected JSON array');
    } catch (err) {
        if (DEBUG) console.warn(`Server listing failed for ${dirUrl}:`, err);
        return { folderCount: 0, fileCount: 0 };
    }

    const stats = { folderCount: 0, fileCount: 0 };
    const subdirPromises = [];

    for (const item of items) {
        const rawName = item.name.endsWith('/') ? item.name.slice(0, -1) : item.name;
        if (rawName.startsWith('.') || rawName.startsWith('_')) continue;

        const base = dirUrl.endsWith('/') ? dirUrl : dirUrl + '/';
        const childUrl = base + encodeURIComponent(rawName) + (item.is_dir ? '/' : '');

        if (item.is_dir) {
            const dirNode = {
                name: rawName,
                type: 'directory',
                handle: createServerDirectoryHandle(rawName, childUrl),
                entries: {},
            };
            parentNode.entries[rawName] = dirNode;
            stats.folderCount++;
            subdirPromises.push(
                readServerDirectory(childUrl, dirNode, depth + 1).then((s) => {
                    stats.folderCount += s.folderCount;
                    stats.fileCount += s.fileCount;
                })
            );
        } else {
            parentNode.entries[rawName] = {
                name: rawName,
                type: 'file',
                handle: createServerFileHandle(rawName, childUrl),
            };
            stats.fileCount++;
        }
    }

    await Promise.all(subdirPromises);
    return stats;
}

/**
 * Detect HTTP context, fetch the directory the page lives under, and render
 * the resulting subtree in the file pane. Idempotent — safe to re-call.
 */
async function loadServerDirectory() {
    if (!(location.protocol === 'http:' || location.protocol === 'https:')) return;

    // Compute the directory URL the file tree should be rooted at.
    //
    //   <project>/working/         → root = <project>/working/
    //   <project>/working/x/y/     → root = <project>/working/x/y/
    //   <project>/working          → root = <project>/working/    (no-slash
    //                                 canonical-folder URL — the dispatcher
    //                                 routes mdedit here directly without
    //                                 a redirect, so we infer "directory"
    //                                 from the absence of a `.` in the
    //                                 last segment rather than stripping
    //                                 back to the parent.)
    //   <project>/x/y/mdedit.html  → root = <project>/x/y/        (the leaf
    //                                 segment IS a file; strip to parent.)
    //
    // The rule: if the last path segment contains a "." it's a file,
    // strip it; otherwise treat the whole path as the directory.
    let href = window.location.href.split('?')[0].split('#')[0];
    let baseUrl;
    if (href.endsWith('/')) {
        baseUrl = href;
    } else {
        const lastSlash = href.lastIndexOf('/');
        const lastSeg = lastSlash >= 0 ? href.substring(lastSlash + 1) : href;
        if (lastSeg.indexOf('.') !== -1) {
            // Looks like a file (has an extension) — strip to parent.
            baseUrl = lastSlash >= 0 ? href.substring(0, lastSlash + 1) : href + '/';
        } else {
            // Looks like a directory — append the trailing slash so all
            // subsequent listing URLs are computed correctly.
            baseUrl = href + '/';
        }
    }

    // Only enter server-source mode if the host actually serves JSON directory
    // listings (zddc-server / Caddy). On a plain static host the probe fails
    // and we must leave "Add Local Directory" visible so the user can still
    // load local files.
    //
    // 403 means the host is a zddc-server but the user lacks `r` on this
    // directory (a "no list" permission posture). Show a clear message so
    // the user understands why the tree is empty.
    try {
        const resp = await fetch(baseUrl, { headers: { 'Accept': 'application/json' }, cache: 'no-cache' });
        if (resp.status === 403) {
            showServerForbiddenMessage();
            return;
        }
        if (!resp.ok) return;
        const items = await resp.json();
        if (!Array.isArray(items)) return;
    } catch (_) {
        return;
    }

    serverSourceMode = true;

    const rootName = (() => {
        const path = baseUrl.replace(/\/$/, '');
        const seg = path.substring(path.lastIndexOf('/') + 1);
        return seg || baseUrl;
    })();

    fileTree = {
        name: rootName,
        type: 'directory',
        handle: createServerDirectoryHandle(rootName, baseUrl),
        entries: {},
    };

    // Surface refresh. The server now exposes a CRUD file API, so write
    // controls (new file, save, delete) stay enabled — the polyfill
    // routes their writes through PUT/DELETE/POST. "Add Local Directory"
    // is de-emphasized so the user can still load a local folder if they
    // want, but server-mode is now the default working mode.
    const refreshBtn = document.getElementById('refreshHeaderBtn');
    if (refreshBtn) refreshBtn.classList.remove('hidden');
    const addDirBtn = document.getElementById('addDirectoryBtn');
    if (addDirBtn) {
        addDirBtn.classList.remove('btn-primary');
        addDirBtn.classList.add('btn--subtle');
    }

    const stats = await readServerDirectory(baseUrl, fileTree, 0);
    renderFileTree();
    updateStatusCounts(stats.folderCount, stats.fileCount);
}

/**
 * Start monitoring files for external changes
 */
function startFileChangeMonitoring() {
    setInterval(async () => {
        for (const [filePath, editorInstance] of editorInstances) {
            try {
                const fileHandle = editorInstance.fileHandle;
                if (!fileHandle) continue;
                if (fileHandle._readOnly) continue;

                const file = await fileHandle.getFile();
                const currentLastModified = file.lastModified;
                const storedLastModified = editorInstance.lastModified;

                if (storedLastModified && currentLastModified !== storedLastModified) {
                    if (DEBUG) console.log(`File ${filePath} changed externally`);
                    
                    const action = confirm(
                        `File "${filePath}" has been modified by another application.\n\n` +
                        'Click OK to reload from disk (discards unsaved changes)\n' +
                        'Click Cancel to keep current version'
                    );

                    if (action) {
                        await reloadFileFromDisk(filePath);
                    } else {
                        editorInstance.lastModified = currentLastModified;
                    }
                }
            } catch (error) {
                if (DEBUG) console.debug(`Error checking file ${filePath}:`, error.message);
            }
        }
    }, 3000);
}
