// engine/scan-project/team-planner.ts — AC-18/19/20 for SPEC-134
// Generates a team execution plan using topological sort on cross-module deps
// ---------------------------------------------------------------------------
// Model recommendation thresholds
// ---------------------------------------------------------------------------
const FILE_THRESHOLD_HAIKU = 20;
const FILE_THRESHOLD_SONNET = 100;
const MINUTES_PER_PHASE = 30;
function recommendModel(mod) {
    if (mod.estimatedFiles > FILE_THRESHOLD_SONNET) {
        return 'opus';
    }
    if (mod.estimatedFiles >= FILE_THRESHOLD_HAIKU) {
        return 'sonnet';
    }
    return 'haiku';
}
// ---------------------------------------------------------------------------
// Model recommendation with complexity fallback
// ---------------------------------------------------------------------------
function recommendModelWithComplexity(mod, result) {
    if (mod.estimatedFiles > FILE_THRESHOLD_SONNET) {
        return 'opus';
    }
    const hasHighComplexity = result?.analysis.complexityMetrics.some((m) => m.avgComplexity > 20) ?? false;
    if (hasHighComplexity) {
        return 'opus';
    }
    if (mod.estimatedFiles >= FILE_THRESHOLD_HAIKU) {
        return 'sonnet';
    }
    return 'haiku';
}
// ---------------------------------------------------------------------------
// Topological sort using Kahn's algorithm
// Returns array of phases (each phase is an array of module names)
// ---------------------------------------------------------------------------
function topoSortPhases(moduleNames, deps) {
    // Build adjacency: from -> [to] and in-degree count
    const inDegree = new Map();
    const adjacency = new Map();
    for (const name of moduleNames) {
        inDegree.set(name, 0);
        adjacency.set(name, []);
    }
    for (const dep of deps) {
        // dep.from depends on dep.to → dep.from must come AFTER dep.to
        if (!moduleNames.includes(dep.from) || !moduleNames.includes(dep.to)) {
            continue;
        }
        adjacency.get(dep.to)?.push(dep.from);
        inDegree.set(dep.from, (inDegree.get(dep.from) ?? 0) + 1);
    }
    const phases = [];
    const remaining = new Set(moduleNames);
    while (remaining.size > 0) {
        // Collect all nodes with in-degree 0 (no unresolved deps)
        const phase = [...remaining].filter((name) => (inDegree.get(name) ?? 0) === 0);
        if (phase.length === 0) {
            // Cycle detected — add remaining nodes as final phase
            phases.push([...remaining]);
            break;
        }
        phases.push(phase);
        // Remove phase nodes and update in-degrees
        for (const name of phase) {
            remaining.delete(name);
            for (const dependent of adjacency.get(name) ?? []) {
                inDegree.set(dependent, (inDegree.get(dependent) ?? 1) - 1);
            }
        }
    }
    return phases;
}
// ---------------------------------------------------------------------------
// Duration formatter
// ---------------------------------------------------------------------------
function formatDuration(phaseCount) {
    const totalMinutes = phaseCount * MINUTES_PER_PHASE;
    if (totalMinutes < 60) {
        return `${totalMinutes}min`;
    }
    const hours = Math.floor(totalMinutes / 60);
    const minutes = totalMinutes % 60;
    return minutes === 0 ? `${hours}h` : `${hours}h ${minutes}min`;
}
// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------
export function generateTeamPlan(modules, moduleResults, crossAnalysis, specsGenerated) {
    if (modules.length === 0) {
        return {
            teamSize: 0,
            phases: [],
            estimatedDuration: '0min',
            teammatePrompts: [],
        };
    }
    const moduleNames = modules.map((m) => m.name);
    const phaseGroups = topoSortPhases(moduleNames, crossAnalysis.dependencies);
    const phases = phaseGroups.map((group, idx) => ({
        phase: idx + 1,
        teammates: group.map((name) => `teammate-${name}`),
        parallel: group.length > 1,
    }));
    const teammatePrompts = modules.map((mod, idx) => {
        const result = moduleResults.find((r) => r.module.name === mod.name);
        return {
            name: `teammate-${mod.name}`,
            specId: specsGenerated[idx] ?? '',
            model: recommendModelWithComplexity(mod, result),
        };
    });
    return {
        teamSize: modules.length,
        phases,
        estimatedDuration: formatDuration(phaseGroups.length),
        teammatePrompts,
    };
}
// Convenience re-export for simple model recommendation (used in tests)
export { recommendModel };
//# sourceMappingURL=team-planner.js.map