// Planu — Shared detection utilities for project analysis
import { readFile, access } from 'node:fs/promises';
import { join } from 'node:path';
import { glob } from 'glob';
const IGNORE_DIRS = [
    'node_modules/**',
    'dist/**',
    'build/**',
    '.git/**',
    'vendor/**',
    '__pycache__/**',
    '.next/**',
    '.nuxt/**',
    'target/**',
    'coverage/**',
];
export async function fileExists(basePath, relativePath) {
    try {
        await access(join(basePath, relativePath));
        return true;
    }
    catch {
        return false;
    }
}
export async function hasAnyFile(basePath, patterns) {
    for (const pattern of patterns) {
        try {
            const matches = await glob(pattern, {
                cwd: basePath,
                nodir: true,
                maxDepth: 3,
                dot: true,
            });
            if (matches.length > 0) {
                return true;
            }
        }
        catch {
            // Glob error, skip
        }
    }
    return false;
}
export async function collectDependencies(projectPath) {
    const deps = new Set();
    // package.json (Node/TS/JS)
    await collectNodeDeps(projectPath, deps);
    // requirements.txt (Python)
    await collectPythonRequirements(projectPath, deps);
    // pyproject.toml (Python)
    await collectPyprojectDeps(projectPath, deps);
    // go.mod (Go)
    await collectGoDeps(projectPath, deps);
    // Gemfile (Ruby)
    await collectRubyDeps(projectPath, deps);
    // Cargo.toml (Rust)
    await collectRustDeps(projectPath, deps);
    // composer.json (PHP)
    await collectPhpDeps(projectPath, deps);
    return deps;
}
async function collectNodeDeps(projectPath, deps) {
    try {
        const pkgJson = JSON.parse(await readFile(join(projectPath, 'package.json'), 'utf-8'));
        for (const dep of Object.keys(pkgJson.dependencies ?? {})) {
            deps.add(dep);
        }
        for (const dep of Object.keys(pkgJson.devDependencies ?? {})) {
            deps.add(dep);
        }
    }
    catch {
        // No package.json
    }
}
async function collectPythonRequirements(projectPath, deps) {
    try {
        const content = await readFile(join(projectPath, 'requirements.txt'), 'utf-8');
        for (const line of content.split('\n')) {
            const trimmed = line.trim();
            if (trimmed && !trimmed.startsWith('#')) {
                const pkgName = trimmed.split(/[>=<!~\s]/)[0];
                if (pkgName) {
                    deps.add(pkgName.toLowerCase());
                }
            }
        }
    }
    catch {
        // No requirements.txt
    }
}
async function collectPyprojectDeps(projectPath, deps) {
    try {
        const content = await readFile(join(projectPath, 'pyproject.toml'), 'utf-8');
        const depMatches = content.matchAll(/"([a-zA-Z0-9_-]+)(?:[>=<!~].*)?"/g);
        for (const match of depMatches) {
            /* v8 ignore next 1 */
            if (match[1]) {
                deps.add(match[1].toLowerCase());
            }
        }
    }
    catch {
        // No pyproject.toml
    }
}
async function collectGoDeps(projectPath, deps) {
    try {
        const content = await readFile(join(projectPath, 'go.mod'), 'utf-8');
        const lines = content.split('\n');
        let inRequire = false;
        for (const line of lines) {
            const trimmed = line.trim();
            if (trimmed === 'require (') {
                inRequire = true;
                continue;
            }
            if (trimmed === ')') {
                inRequire = false;
                continue;
            }
            if (inRequire && trimmed) {
                const parts = trimmed.split(/\s+/);
                /* v8 ignore next 1 */
                if (parts[0]) {
                    deps.add(parts[0]);
                }
            }
        }
    }
    catch {
        // No go.mod
    }
}
async function collectRubyDeps(projectPath, deps) {
    try {
        const content = await readFile(join(projectPath, 'Gemfile'), 'utf-8');
        const gemMatches = content.matchAll(/gem\s+['"]([^'"]+)['"]/g);
        for (const match of gemMatches) {
            /* v8 ignore next 1 */
            if (match[1]) {
                deps.add(match[1]);
            }
        }
    }
    catch {
        // No Gemfile
    }
}
async function collectRustDeps(projectPath, deps) {
    try {
        const content = await readFile(join(projectPath, 'Cargo.toml'), 'utf-8');
        let inDeps = false;
        for (const line of content.split('\n')) {
            if (/^\[.*dependencies.*\]/.exec(line)) {
                inDeps = true;
                continue;
            }
            if (/^\[/.exec(line)) {
                inDeps = false;
                continue;
            }
            if (inDeps) {
                const match = /^([a-zA-Z0-9_-]+)\s*=/.exec(line);
                if (match?.[1]) {
                    deps.add(match[1]);
                }
            }
        }
    }
    catch {
        // No Cargo.toml
    }
}
async function collectPhpDeps(projectPath, deps) {
    try {
        const composerJson = JSON.parse(await readFile(join(projectPath, 'composer.json'), 'utf-8'));
        for (const dep of Object.keys(composerJson.require ?? {})) {
            deps.add(dep);
        }
        for (const dep of Object.keys(composerJson['require-dev'] ?? {})) {
            deps.add(dep);
        }
    }
    catch {
        // No composer.json
    }
}
export async function loadStackSignatures() {
    try {
        const configPath = new URL('../config/stack-signatures.json', import.meta.url);
        const content = await readFile(configPath, 'utf-8');
        return JSON.parse(content);
    }
    catch {
        return { languages: {}, frameworks: {}, packageManagers: {}, databases: {} };
    }
}
export async function loadArchPatterns() {
    try {
        const configPath = new URL('../config/architecture-patterns.json', import.meta.url);
        const content = await readFile(configPath, 'utf-8');
        return JSON.parse(content);
    }
    catch {
        return { patterns: {} };
    }
}
export async function readJsonFile(filePath) {
    try {
        const content = await readFile(filePath, 'utf-8');
        return JSON.parse(content);
    }
    catch {
        return null;
    }
}
export async function readTextFile(filePath) {
    try {
        return await readFile(filePath, 'utf-8');
    }
    catch {
        return null;
    }
}
export { IGNORE_DIRS };
//# sourceMappingURL=detection-utils.js.map