import { filterBlocked, detectCycleMembers } from './dependency-filter.js';
import { filterConflicting } from './conflict-filter.js';
import { scoreSpec } from './scorer.js';
// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------
/**
 * SPEC-686 Scenarios 1-11: Resolve the next spec to implement.
 *
 * Algorithm:
 *   1. Filter approved only
 *   2. filterBlocked(candidates, allSpecs)     [remove deps not done, cycles]
 *   3. filterConflicting(candidates, activeSpecs) [remove file conflicts with implementing]
 *   4. Sort by scoreSpec() DESC, then by id ASC (tie-break)
 *   5. Return top-1 as NextSpecResult
 *
 * @param _projectPath - absolute path to project root (reserved for future use)
 * @param allSpecs - full list of all specs in the project
 */
export function resolveNextSpec(_projectPath, allSpecs) {
    return Promise.resolve(computeNextSpec(allSpecs));
}
function computeNextSpec(allSpecs) {
    // Scenario 8: empty spec list
    if (allSpecs.length === 0) {
        return { spec: null, reason: 'No specs in project yet' };
    }
    // Step 1: Filter approved candidates
    const approved = allSpecs.filter((s) => s.status === 'approved');
    if (approved.length === 0) {
        return {
            spec: null,
            reason: 'All approved specs are blocked or conflicting. Review blockers in roadmap.md',
        };
    }
    // Step 2: Filter blocked by dependencies (includes cycle detection)
    const cycleMembers = detectCycleMembers(allSpecs);
    const unblocked = filterBlocked(approved, allSpecs);
    // Scenario 9: build reason mentioning cycles if any approved specs are in cycles
    if (cycleMembers.size > 0) {
        const cycledApproved = approved.filter((s) => cycleMembers.has(s.id));
        if (cycledApproved.length > 0 && unblocked.length === 0) {
            const cycleIds = [...cycleMembers].join(', ');
            return {
                spec: null,
                reason: `Cycle detected involving ${cycleIds} — review dependencies`,
            };
        }
    }
    if (unblocked.length === 0) {
        return {
            spec: null,
            reason: 'All approved specs are blocked or conflicting. Review blockers in roadmap.md',
        };
    }
    // Step 3: Filter conflicting with implementing specs
    const activeSpecs = allSpecs.filter((s) => s.status === 'implementing');
    const candidates = filterConflicting(unblocked, activeSpecs);
    if (candidates.length === 0) {
        return {
            spec: null,
            reason: 'All approved specs are blocked or conflicting. Review blockers in roadmap.md',
        };
    }
    // Step 4: Sort by ROI score DESC, then by id ASC for tie-breaking
    const sorted = [...candidates].sort((a, b) => {
        const scoreDiff = scoreSpec(b) - scoreSpec(a);
        if (scoreDiff !== 0) {
            return scoreDiff;
        }
        return a.id.localeCompare(b.id);
    });
    const winner = sorted[0];
    if (!winner) {
        return {
            spec: null,
            reason: 'All approved specs are blocked or conflicting. Review blockers in roadmap.md',
        };
    }
    const score = scoreSpec(winner);
    const reason = `Highest ROI: ${score.toFixed(4)} score, no blockers`;
    return {
        spec: { id: winner.id, title: winner.title },
        reason,
    };
}
//# sourceMappingURL=index.js.map