// engine/spec-decomposer/file-mapper.ts — Map work units to specific files (SPEC-157)
// Given work units and a full list of project files, assigns concrete file paths
// to each unit based on path segment heuristics.
// ---------------------------------------------------------------------------
// Path segment heuristics
// ---------------------------------------------------------------------------
/** Map unit IDs to path segment patterns that indicate file relevance. */
const UNIT_PATH_HINTS = {
    types: ['types/', '/types.ts', 'type.ts'],
    engine: ['engine/', 'analyzer', 'calculator', 'processor', 'resolver', 'detector'],
    storage: ['storage/', 'store.ts', '-store.ts', 'repository', 'persistence'],
    tool: ['tools/', 'handler.ts', 'register-'],
    tests: ['tests/', '.test.ts', '.spec.ts'],
    general: [],
};
/**
 * Score how relevant a file path is for a given unit ID.
 * Returns 0 for irrelevant, higher values for stronger matches.
 */
function scoreFilePath(filePath, unitId) {
    const lower = filePath.toLowerCase();
    const categoryId = unitId.replace(/^unit-/, '');
    const hints = UNIT_PATH_HINTS[categoryId] ?? UNIT_PATH_HINTS.general ?? [];
    let score = 0;
    for (const hint of hints) {
        if (lower.includes(hint)) {
            score += 2;
        }
    }
    // Bonus: file path contains a keyword from the unit's criteria (caller may inject)
    return score;
}
// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------
/**
 * Map work units to concrete file paths.
 *
 * Strategy:
 * 1. Each unit starts with its suggestedFiles (from analyzer).
 * 2. For remaining files in allFiles not yet assigned, we use path-hint scoring
 *    to assign them to the best-matching unit.
 * 3. Files with score 0 for all units are distributed to the last unit (fallback).
 */
export function mapUnitsToFiles(units, allFiles) {
    if (units.length === 0) {
        return [];
    }
    // Seed each mapped unit with its suggestedFiles
    const mapped = units.map((u) => ({
        id: u.id,
        title: u.title,
        criteria: u.criteria,
        files: [...u.suggestedFiles],
        recommendedModel: u.recommendedModel,
        estimatedHours: u.estimatedHours,
    }));
    // Track which files are already covered
    const assignedFiles = new Set(units.flatMap((u) => u.suggestedFiles));
    // Assign remaining files to best-matching unit
    for (const file of allFiles) {
        if (assignedFiles.has(file)) {
            continue;
        }
        let bestUnitIndex = mapped.length - 1; // fallback: last unit
        let bestScore = -1;
        for (let i = 0; i < mapped.length; i++) {
            const unit = mapped[i];
            if (!unit) {
                continue;
            }
            const score = scoreFilePath(file, unit.id);
            if (score > bestScore) {
                bestScore = score;
                bestUnitIndex = i;
            }
        }
        const target = mapped[bestUnitIndex];
        if (target && !target.files.includes(file)) {
            target.files.push(file);
            assignedFiles.add(file);
        }
    }
    return mapped;
}
/**
 * De-duplicate files within each mapped unit and ensure uniqueness.
 * Called after mapUnitsToFiles() as a clean-up step.
 */
export function deduplicateMappedFiles(units) {
    return units.map((unit) => ({
        ...unit,
        files: [...new Set(unit.files)],
    }));
}
//# sourceMappingURL=file-mapper.js.map