import { access, realpath } from 'node:fs/promises';
import { dirname, posix, resolve, sep } from 'node:path';
import { CliError } from '../errors/index.js';
export async function resolveProjectRoot(cwd) {
    let current = resolve(cwd);
    while (true) {
        try {
            await access(resolve(current, '.git'));
            return current;
        }
        catch {
            const parent = dirname(current);
            if (parent === current) {
                break;
            }
            current = parent;
        }
    }
    throw new CliError(`Unable to resolve project root from ${cwd}`, 2);
}
export function resolveScopeRoot(scope, cwd, home) {
    if (scope === 'user') {
        return resolve(home);
    }
    return resolve(cwd);
}
export function toPosixPath(pathValue) {
    return pathValue.replaceAll('\\', '/');
}
export function normalizeToPosixPath(pathValue) {
    return posix.normalize(toPosixPath(pathValue));
}
export function validatePathWithinScope(candidatePath, scopeRoot) {
    const resolvedScopeRoot = resolve(scopeRoot);
    const resolvedCandidatePath = resolve(candidatePath);
    const isInside = resolvedCandidatePath === resolvedScopeRoot ||
        resolvedCandidatePath.startsWith(`${resolvedScopeRoot}${sep}`);
    if (!isInside) {
        throw new CliError(`Path ${candidatePath} is outside scope root ${scopeRoot}`);
    }
    return resolvedCandidatePath;
}
export async function validateRealPathWithinScope(candidatePath, scopeRoot) {
    const resolvedCandidatePath = validatePathWithinScope(candidatePath, scopeRoot);
    let realScopeRoot;
    let realCandidatePath;
    try {
        [realScopeRoot, realCandidatePath] = await Promise.all([
            realpath(resolve(scopeRoot)),
            realpath(resolvedCandidatePath),
        ]);
    }
    catch (error) {
        const detail = error instanceof Error ? `: ${error.message}` : '';
        throw new CliError(`Unable to resolve real path for ${candidatePath} within scope root ${scopeRoot}${detail}`);
    }
    validatePathWithinScope(realCandidatePath, realScopeRoot);
    return { realScopeRoot, realPath: realCandidatePath };
}
