/**
 * scope-lookup.mjs — cross-scope milestone resolution (C12 subtask 3).
 *
 * Extracted from commands/roadmap.mjs so seeds/roadmap CLIs can share the
 * same lookup without duplicating scope enumeration or the ambiguity
 * handling. The original inline `findMilestoneScope()` inside
 * `commands/roadmap.mjs` (line 91-103) is now delegated to this module so
 * there is exactly one implementation.
 *
 * Two flavors:
 *
 *   findMilestoneScopes(targetDir, milestoneId)
 *     → returns the array of scopes that contain the given milestone id.
 *       Useful when the caller wants to format its own error.
 *
 *   resolveMilestoneScope(targetDir, milestoneId)
 *     → returns { scope, error } — convenience wrapper.
 *       error === null when exactly one match; otherwise error carries a
 *       ready-made message string the CLI can surface via fail().
 */

import { loadRoadmapForScope } from './io.mjs'
import { listRoadmapScopes } from './paths.mjs'

/**
 * Return the list of scopes whose roadmap contains `milestoneId`. Empty
 * array when no roadmap claims the milestone.
 *
 * Relies on `loadRoadmapForScope` to surface every milestone — including
 * empty-phases milestones that live only in the legacy blob. See
 * `overlayLegacyMilestoneFields` in io.mjs: it appends legacy-only
 * milestones onto the phases/-reconstructed list so the lookup sees a
 * freshly-added empty-phases milestone, which fixes the `roadmap
 * add-milestone` → `roadmap add-phase` round-trip on scopes whose phases/
 * layout is already populated.
 */
export function findMilestoneScopes(targetDir, milestoneId) {
	const hits = []
	for (const scope of listRoadmapScopes(targetDir)) {
		const rm = loadRoadmapForScope(targetDir, scope)
		if (!rm || !Array.isArray(rm.milestones)) continue
		if (rm.milestones.some((m) => m && m.id === milestoneId)) hits.push(scope)
	}
	return hits
}

/**
 * Resolve a milestone id to its scope. Returns:
 *   { scope, error }
 * - scope === a scope string, error === null when exactly one match.
 * - scope === null, error === 'not-found' when no scope claims the id.
 * - scope === null, error === 'ambiguous: <scope-list>' when >1 scope claims it.
 *
 * Callers convert the error string into a user-facing message (usually via
 * fail()).
 */
export function resolveMilestoneScope(targetDir, milestoneId) {
	const hits = findMilestoneScopes(targetDir, milestoneId)
	if (hits.length === 0) return { scope: null, error: 'not-found' }
	if (hits.length > 1) return { scope: null, error: `ambiguous: ${hits.join(', ')}` }
	return { scope: hits[0], error: null }
}
