// tools/resolve-project-path.ts — SPEC-341/SPEC-509: Zero-config auto-detect projectPath.
//
// Priority order:
//  1. Explicit projectPath or projectId passed by the caller (fastest path, no I/O)
//  2. PLANU_PROJECT_PATH environment variable
//  3. git rev-parse --show-toplevel (SPEC-509: detect from current working directory)
//  4. Single registered project in the global registry (auto-detect)
//  5. Multiple registered projects → ambiguous error with list
//  6. No registered projects → missing error
//
// This module is intentionally side-effect-free: it reads the global registry
// and the env var but never mutates any state.
import { spawnSync } from 'node:child_process';
import { hashProjectPath } from '../storage/base-store.js';
import { getProjects } from '../storage/global-projects-store.js';
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
/**
 * SPEC-509: Detect the git repository root from the current working directory.
 * Runs `git rev-parse --show-toplevel` synchronously (non-blocking, fast).
 * Returns the git root path or null when not inside a git repo.
 */
export function detectGitRoot() {
    try {
        const result = spawnSync('git', ['rev-parse', '--show-toplevel'], {
            cwd: process.cwd(),
            encoding: 'utf-8',
            timeout: 3000,
        });
        if (result.status === 0 && result.stdout) {
            return result.stdout.trim() || null;
        }
        return null;
    }
    catch {
        return null;
    }
}
/**
 * Derive a human-readable project name from its absolute path.
 * Uses the last non-empty path segment (the directory name).
 */
function projectNameFromPath(projectPath) {
    const parts = projectPath.replace(/\\/g, '/').split('/').filter(Boolean);
    return parts[parts.length - 1] ?? projectPath;
}
/**
 * Convert a RegisteredProject entry into a compact summary for error responses.
 */
function toSummary(p) {
    return {
        id: p.hash,
        path: p.path,
        name: projectNameFromPath(p.path),
    };
}
// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------
/**
 * Attempt to resolve a projectId + projectPath from the provided inputs.
 *
 * When the caller passes `projectPath` or `projectId` explicitly, this
 * function returns immediately without hitting the filesystem.
 *
 * When neither is provided it falls back to:
 *  1. `PLANU_PROJECT_PATH` env var
 *  2. Single registered project in the global registry
 *  3. Ambiguous / missing error with the full registered-project list
 *
 * @param params.projectId  - Optional explicit project hash
 * @param params.projectPath - Optional explicit absolute path
 * @returns ProjectAutoDetectResult discriminated union
 */
export async function resolveProjectPath(params) {
    // 1. Explicit projectPath — highest priority
    const explicitPath = params.projectPath?.trim();
    if (explicitPath) {
        return {
            kind: 'resolved',
            projectId: hashProjectPath(explicitPath),
            projectPath: explicitPath,
            autoDetected: false,
        };
    }
    // 2. Explicit projectId — second priority
    const explicitId = params.projectId?.trim();
    if (explicitId) {
        // Look up the original path from the global registry so downstream tools
        // (session-context, autopilot, hooks) get a usable projectPath instead of ''.
        // Falls back to empty path when the projectId isn't registered (test fixtures,
        // freshly-bootstrapped projects).
        let recoveredPath = '';
        try {
            const projects = await getProjects();
            const match = projects.find((p) => p.hash === explicitId);
            if (match) {
                recoveredPath = match.path;
            }
        }
        catch {
            // Registry unreadable — keep recoveredPath empty
        }
        return {
            kind: 'resolved',
            projectId: explicitId,
            projectPath: recoveredPath,
            autoDetected: false,
        };
    }
    // 3. PLANU_PROJECT_PATH environment variable
    const envPath = process.env.PLANU_PROJECT_PATH?.trim();
    if (envPath) {
        return {
            kind: 'resolved',
            projectId: hashProjectPath(envPath),
            projectPath: envPath,
            autoDetected: true,
        };
    }
    // 4. SPEC-509: git rev-parse --show-toplevel — detect from current working directory
    const gitRoot = detectGitRoot();
    if (gitRoot) {
        return {
            kind: 'resolved',
            projectId: hashProjectPath(gitRoot),
            projectPath: gitRoot,
            autoDetected: true,
        };
    }
    // 5. Global registry lookup
    let projects;
    try {
        projects = await getProjects();
    }
    catch {
        // Registry unreadable → treat as missing
        projects = [];
    }
    if (projects.length === 1) {
        // Exactly one registered project → auto-use it
        const only = projects[0];
        /* v8 ignore next 3 */
        if (only === undefined) {
            return { kind: 'missing', registeredProjects: [] };
        }
        return {
            kind: 'resolved',
            projectId: only.hash,
            projectPath: only.path,
            autoDetected: true,
        };
    }
    const summaries = projects.map(toSummary);
    if (projects.length > 1) {
        return { kind: 'ambiguous', registeredProjects: summaries };
    }
    return { kind: 'missing', registeredProjects: [] };
}
//# sourceMappingURL=resolve-project-path.js.map