/**
 * globs.mjs — glob matcher + risk-class path classifier (C29).
 */

/**
 * Convert a simple glob pattern to a RegExp.
 * Supports ** (any path segments) and * (any chars except /).
 * Bounded: rejects patterns longer than 200 chars to prevent ReDoS (T-10-02).
 */
export function globToRegex(pattern) {
	if (pattern.length > 200) return null
	let re = ''
	let i = 0
	while (i < pattern.length) {
		const ch = pattern[i]
		if (ch === '*' && pattern[i + 1] === '*') {
			// ** matches any path segments (including empty)
			re += '.*'
			i += 2
			// Skip trailing / after **
			if (pattern[i] === '/') i++
		} else if (ch === '*') {
			// * matches anything except /
			re += '[^/]*'
			i++
		} else if (ch === '?') {
			re += '[^/]'
			i++
		} else if ('.+^${}()|[]\\'.includes(ch)) {
			re += '\\' + ch
			i++
		} else {
			re += ch
			i++
		}
	}
	return new RegExp('^' + re + '$')
}

/**
 * Match a file path against an array of glob patterns.
 * Returns the first matching pattern or null.
 */
export function matchGlobs(filepath, patterns) {
	for (const pattern of patterns) {
		const re = globToRegex(pattern)
		if (re && re.test(filepath)) return pattern
	}
	return null
}

/**
 * Classify a single file path against the risk map.
 * Checks critical first, then elevated, then safe. Unmatched = Normal.
 */
export function classifyPath(filepath, riskMap) {
	// Critical wins — check first
	const critMatch = matchGlobs(filepath, riskMap.critical_paths || [])
	if (critMatch) return { risk_class: 'Critical', matched_pattern: critMatch }

	const elevMatch = matchGlobs(filepath, riskMap.elevated_paths || [])
	if (elevMatch) return { risk_class: 'Elevated', matched_pattern: elevMatch }

	const safeMatch = matchGlobs(filepath, riskMap.safe_paths || [])
	if (safeMatch) return { risk_class: 'Safe', matched_pattern: safeMatch }

	return { risk_class: 'Normal', matched_pattern: null }
}
