/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import * as os from 'node:os';
import * as path from 'node:path';
import * as fs from 'node:fs';
import { opendir } from 'node:fs/promises';
const MAX_SUGGESTIONS = 50;
const MATCH_BUFFER_MULTIPLIER = 3;
export function expandHomeDir(p) {
    if (!p) {
        return '';
    }
    let expandedPath = p;
    if (p.toLowerCase().startsWith('%userprofile%')) {
        expandedPath = os.homedir() + p.substring('%userprofile%'.length);
    }
    else if (p === '~' || p.startsWith('~/')) {
        expandedPath = os.homedir() + p.substring(1);
    }
    return path.normalize(expandedPath);
}
function parsePartialPath(partialPath) {
    const isHomeExpansion = partialPath.startsWith('~');
    const expandedPath = expandHomeDir(partialPath || '.');
    let searchDir;
    let filter;
    if (partialPath === '' ||
        partialPath.endsWith('/') ||
        partialPath.endsWith(path.sep)) {
        searchDir = expandedPath;
        filter = '';
    }
    else {
        searchDir = path.dirname(expandedPath);
        filter = path.basename(expandedPath);
        // Special case for ~ because path.dirname('~') can be '.'
        if (isHomeExpansion &&
            !partialPath.includes('/') &&
            !partialPath.includes(path.sep)) {
            searchDir = os.homedir();
            filter = partialPath.substring(1);
        }
    }
    // Calculate result prefix
    let resultPrefix = '';
    if (partialPath === '' ||
        partialPath.endsWith('/') ||
        partialPath.endsWith(path.sep)) {
        resultPrefix = partialPath;
    }
    else {
        const lastSlashIndex = Math.max(partialPath.lastIndexOf('/'), partialPath.lastIndexOf(path.sep));
        if (lastSlashIndex !== -1) {
            resultPrefix = partialPath.substring(0, lastSlashIndex + 1);
        }
        else if (isHomeExpansion) {
            resultPrefix = `~${path.sep}`;
        }
    }
    return { searchDir, filter, isHomeExpansion, resultPrefix };
}
/**
 * Gets directory suggestions based on a partial path.
 * Uses async iteration with fs.opendir for efficient handling of large directories.
 *
 * @param partialPath The partial path typed by the user.
 * @returns A promise resolving to an array of directory path suggestions.
 */
export async function getDirectorySuggestions(partialPath) {
    try {
        const { searchDir, filter, resultPrefix } = parsePartialPath(partialPath);
        if (!fs.existsSync(searchDir) || !fs.statSync(searchDir).isDirectory()) {
            return [];
        }
        const matches = [];
        const filterLower = filter.toLowerCase();
        const showHidden = filter.startsWith('.');
        const dir = await opendir(searchDir);
        try {
            for await (const entry of dir) {
                if (!entry.isDirectory()) {
                    continue;
                }
                if (entry.name.startsWith('.') && !showHidden) {
                    continue;
                }
                if (entry.name.toLowerCase().startsWith(filterLower)) {
                    matches.push(entry.name);
                    // Early termination with buffer for sorting
                    if (matches.length >= MAX_SUGGESTIONS * MATCH_BUFFER_MULTIPLIER) {
                        break;
                    }
                }
            }
        }
        finally {
            await dir.close().catch(() => { });
        }
        // Use the separator style from user's input for consistency
        const userSep = resultPrefix.includes('/') ? '/' : path.sep;
        return matches
            .sort()
            .slice(0, MAX_SUGGESTIONS)
            .map((name) => resultPrefix + name + userSep);
    }
    catch (_) {
        return [];
    }
}
//# sourceMappingURL=directoryUtils.js.map