// Planu — Framework, ORM, and database detection
import { join } from 'node:path';
import { fileExists, hasAnyFile, collectDependencies, readJsonFile } from './detection-utils.js';
/**
 * Detect the primary framework from indicator files and dependencies.
 */
export async function detectFramework(projectPath, signatures) {
    // Check indicator files first (most reliable)
    for (const [fw, sig] of Object.entries(signatures.frameworks)) {
        for (const indicator of sig.indicators) {
            if (await hasAnyFile(projectPath, [indicator])) {
                return fw;
            }
        }
    }
    // Check dependencies
    const deps = await collectDependencies(projectPath);
    for (const [fw, sig] of Object.entries(signatures.frameworks)) {
        for (const dep of sig.dependencies) {
            if (deps.has(dep)) {
                return fw;
            }
        }
    }
    return null;
}
/**
 * Detect the framework version from dependency files.
 */
export async function detectFrameworkVersion(projectPath, framework, signatures) {
    if (!framework) {
        return null;
    }
    const sig = signatures.frameworks[framework];
    if (!sig) {
        return null;
    }
    // Try to find the version in package.json
    const pkgJson = await readJsonFile(join(projectPath, 'package.json'));
    if (pkgJson) {
        const allDeps = {
            ...(pkgJson.dependencies ?? {}),
            ...(pkgJson.devDependencies ?? {}),
        };
        for (const dep of sig.dependencies) {
            if (allDeps[dep]) {
                return allDeps[dep] ?? null;
            }
        }
    }
    return null;
}
/**
 * Detect the database engine from indicator files and dependencies.
 */
export async function detectDatabase(projectPath, signatures) {
    const deps = await collectDependencies(projectPath);
    for (const [, sig] of Object.entries(signatures.databases)) {
        // Check indicator files
        for (const indicator of sig.indicators) {
            if (await hasAnyFile(projectPath, [indicator])) {
                if (isKnownEngine(sig.engine)) {
                    return sig.engine;
                }
            }
        }
        // Check dependencies
        for (const dep of sig.dependencies) {
            if (deps.has(dep)) {
                if (isKnownEngine(sig.engine)) {
                    return sig.engine;
                }
            }
        }
    }
    return 'unknown';
}
const KNOWN_ENGINES = new Set([
    'postgresql',
    'supabase',
    'mysql',
    'sqlite',
    'mongodb',
    'firebase',
    'redis',
    'memcached',
    'valkey',
    'elasticsearch',
    'opensearch',
    'meilisearch',
    'algolia',
    'typesense',
    'influxdb',
    'timescaledb',
    'questdb',
    'neo4j',
    'arangodb',
    'neptune',
    'dgraph',
    'pinecone',
    'weaviate',
    'qdrant',
    'milvus',
    'chromadb',
    'cassandra',
    'scylladb',
    'hbase',
    'clickhouse',
    'cockroachdb',
    'tidb',
    'spanner',
    'planetscale',
    'neon',
    'alloydb',
    'dynamodb',
    'aurora',
    'documentdb',
    'cosmosdb',
    'unknown',
]);
function isKnownEngine(engine) {
    return KNOWN_ENGINES.has(engine);
}
/**
 * Detect ORM/ODM used in the project.
 */
export async function detectOrm(projectPath) {
    const deps = await collectDependencies(projectPath);
    const ormMap = {
        prisma: ['@prisma/client', 'prisma'],
        drizzle: ['drizzle-orm'],
        typeorm: ['typeorm'],
        sequelize: ['sequelize'],
        mongoose: ['mongoose'],
        mikro: ['@mikro-orm/core'],
        objection: ['objection'],
        knex: ['knex'],
        sqlalchemy: ['sqlalchemy'],
        'django-orm': ['django'],
        tortoise: ['tortoise-orm'],
        peewee: ['peewee'],
        gorm: ['gorm.io/gorm'],
        ent: ['entgo.io/ent'],
        diesel: ['diesel'],
        'sea-orm': ['sea-orm'],
        ecto: ['ecto'],
        'active-record': ['activerecord'],
        eloquent: ['illuminate/database'],
    };
    for (const [orm, packages] of Object.entries(ormMap)) {
        for (const pkg of packages) {
            if (deps.has(pkg)) {
                return orm;
            }
        }
    }
    // Check for Prisma schema file
    if (await hasAnyFile(projectPath, ['prisma/schema.prisma'])) {
        return 'prisma';
    }
    // Check for Drizzle config
    if (await hasAnyFile(projectPath, ['drizzle.config.ts', 'drizzle.config.js'])) {
        return 'drizzle';
    }
    return null;
}
/**
 * Detect package manager from lockfiles.
 */
export async function detectPackageManager(projectPath, signatures) {
    for (const [pm, sig] of Object.entries(signatures.packageManagers)) {
        if (await fileExists(projectPath, sig.lockfile)) {
            return pm;
        }
    }
    return null;
}
/**
 * Detect build command from project config files.
 */
export async function detectBuildCommand(projectPath, packageManager) {
    const pkgJson = await readJsonFile(join(projectPath, 'package.json'));
    if (pkgJson) {
        const scripts = pkgJson.scripts;
        if (scripts?.build) {
            return `${pmRunner(packageManager)} run build`;
        }
    }
    if (await fileExists(projectPath, 'Makefile')) {
        return 'make build';
    }
    if (await fileExists(projectPath, 'Cargo.toml')) {
        return 'cargo build';
    }
    if (await fileExists(projectPath, 'go.mod')) {
        return 'go build ./...';
    }
    return null;
}
/**
 * Detect test command from project config files.
 */
export async function detectTestCommand(projectPath, packageManager) {
    const pkgJson = await readJsonFile(join(projectPath, 'package.json'));
    if (pkgJson) {
        const scripts = pkgJson.scripts;
        if (scripts?.test) {
            return `${pmRunner(packageManager)} test`;
        }
    }
    if (await fileExists(projectPath, 'Cargo.toml')) {
        return 'cargo test';
    }
    if (await fileExists(projectPath, 'go.mod')) {
        return 'go test ./...';
    }
    if ((await fileExists(projectPath, 'pytest.ini')) ||
        (await fileExists(projectPath, 'pyproject.toml'))) {
        return 'pytest';
    }
    return null;
}
/**
 * Detect lint command from project config files.
 */
export async function detectLintCommand(projectPath, packageManager) {
    const pkgJson = await readJsonFile(join(projectPath, 'package.json'));
    if (pkgJson) {
        const scripts = pkgJson.scripts;
        if (scripts?.lint) {
            return `${pmRunner(packageManager)} run lint`;
        }
    }
    if (await hasAnyFile(projectPath, ['.eslintrc*', 'eslint.config.*'])) {
        return `${pmRunner(packageManager)} run lint`;
    }
    if (await hasAnyFile(projectPath, ['biome.json', 'biome.jsonc'])) {
        return 'biome check .';
    }
    if (await hasAnyFile(projectPath, ['ruff.toml'])) {
        return 'ruff check .';
    }
    if (await hasAnyFile(projectPath, ['.golangci.yml', '.golangci.yaml'])) {
        return 'golangci-lint run';
    }
    if (await fileExists(projectPath, 'Cargo.toml')) {
        return 'cargo clippy';
    }
    return null;
}
function pmRunner(packageManager) {
    if (packageManager === 'pnpm') {
        return 'pnpm';
    }
    if (packageManager === 'yarn') {
        return 'yarn';
    }
    if (packageManager === 'bun') {
        return 'bun';
    }
    return 'npm';
}
//# sourceMappingURL=framework-detector.js.map