import * as fs from 'node:fs';
import * as path from 'node:path';
import { getWorkspaceChangesDir, readWorkspaceViewStateSync, workspaceStateFileExistsSync, } from './workspace/index.js';
import { FileSystemUtils } from '../utils/file-system.js';
const REPO_DEFAULT_SCHEMA = 'spec-driven';
const WORKSPACE_DEFAULT_SCHEMA = 'workspace-planning';
function pathExistsAsDirectory(candidatePath) {
    try {
        return fs.statSync(candidatePath).isDirectory();
    }
    catch {
        return false;
    }
}
function getSearchStartDirectory(startPath) {
    const resolved = path.resolve(startPath);
    try {
        const stats = fs.statSync(resolved);
        const searchStart = stats.isDirectory() ? resolved : path.dirname(resolved);
        return FileSystemUtils.canonicalizeExistingPath(searchStart);
    }
    catch {
        return resolved;
    }
}
function findNearestAncestor(startPath, predicate) {
    let currentDir = getSearchStartDirectory(startPath);
    while (true) {
        if (predicate(currentDir)) {
            return FileSystemUtils.canonicalizeExistingPath(currentDir);
        }
        const parentDir = path.dirname(currentDir);
        if (parentDir === currentDir) {
            return null;
        }
        currentDir = parentDir;
    }
}
export function findWorkspacePlanningRootSync(startPath = process.cwd()) {
    return findNearestAncestor(startPath, workspaceStateFileExistsSync);
}
export function findRepoPlanningRootSync(startPath = process.cwd()) {
    return findNearestAncestor(startPath, (dirPath) => pathExistsAsDirectory(path.join(dirPath, 'openspec')));
}
function isSameOrDescendant(rootPath, candidatePath) {
    const relative = path.relative(rootPath, candidatePath);
    return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
}
function countPathSegments(candidatePath) {
    return path.resolve(candidatePath).split(path.sep).filter(Boolean).length;
}
function isWindowsLikePath(candidatePath) {
    return /^[A-Za-z]:[\\/]/.test(candidatePath) || candidatePath.startsWith('\\\\');
}
function relativePlanningPath(fromPath, toPath) {
    if (isWindowsLikePath(fromPath) || isWindowsLikePath(toPath)) {
        return path.win32.relative(path.win32.normalize(fromPath), path.win32.normalize(toPath));
    }
    return path.posix.relative(fromPath.replace(/\\/g, '/'), toPath.replace(/\\/g, '/'));
}
function workspacePlanningHome(workspaceRoot) {
    const viewState = readWorkspaceViewStateSync(workspaceRoot);
    return {
        kind: 'workspace',
        root: workspaceRoot,
        changesDir: getWorkspaceChangesDir(workspaceRoot),
        defaultSchema: WORKSPACE_DEFAULT_SCHEMA,
        workspace: {
            name: viewState?.name ?? path.basename(workspaceRoot),
            links: Object.keys(viewState?.links ?? {}).sort((a, b) => a.localeCompare(b)),
        },
    };
}
function repoPlanningHome(repoRoot) {
    return {
        kind: 'repo',
        root: repoRoot,
        changesDir: path.join(repoRoot, 'openspec', 'changes'),
        defaultSchema: REPO_DEFAULT_SCHEMA,
    };
}
export function resolveCurrentPlanningHomeSync(options = {}) {
    const startPath = options.startPath ?? process.cwd();
    const searchStart = getSearchStartDirectory(startPath);
    const workspaceRoot = findWorkspacePlanningRootSync(searchStart);
    const repoRoot = findRepoPlanningRootSync(searchStart);
    if (workspaceRoot && isSameOrDescendant(workspaceRoot, searchStart)) {
        if (!repoRoot || countPathSegments(workspaceRoot) >= countPathSegments(repoRoot)) {
            return workspacePlanningHome(workspaceRoot);
        }
    }
    if (repoRoot) {
        return repoPlanningHome(repoRoot);
    }
    if (options.allowImplicitRepoRoot === false) {
        throw new Error('No OpenSpec planning home found from the current directory.');
    }
    return repoPlanningHome(FileSystemUtils.canonicalizeExistingPath(searchStart));
}
export function getChangeDir(planningHome, changeName) {
    return FileSystemUtils.joinPath(planningHome.changesDir, changeName);
}
export function formatChangeLocation(planningHome, changeName) {
    const changeDir = getChangeDir(planningHome, changeName);
    const relative = relativePlanningPath(planningHome.root, changeDir);
    return relative.length > 0 ? relative : changeDir;
}
//# sourceMappingURL=planning-home.js.map