// eslint-disable-next-line no-duplicate-imports
import { SOURCE_PRIORITY_RANK } from '../types/source-resolution.js';
/**
 * Map source priority to a confidence level.
 */
function priorityToConfidence(priority) {
    const rank = SOURCE_PRIORITY_RANK[priority];
    if (rank >= 40) {
        return 'high';
    }
    if (rank >= 30) {
        return 'medium';
    }
    return 'low';
}
/**
 * Check whether two values are meaningfully different.
 * Handles primitives, dates, and JSON-serializable objects.
 */
function valuesAreDifferent(a, b) {
    if (a === b) {
        return false;
    }
    if (a === null || b === null) {
        return true;
    }
    if (typeof a !== typeof b) {
        return true;
    }
    if (typeof a === 'object') {
        return JSON.stringify(a) !== JSON.stringify(b);
    }
    return true;
}
/**
 * Resolve a conflict among multiple data sources by selecting the
 * highest-priority non-null value.
 *
 * @param sources - Array of data sources, each with a priority and value.
 * @param fieldName - Human-readable name of the field being resolved (for the explanation).
 * @returns The resolved data with full explanation of the decision.
 *
 * @example
 * ```ts
 * const result = resolveConflict([
 *   { priority: 'spec-baseline', value: 'draft', label: 'spec.md' },
 *   { priority: 'progress', value: 'implementing', label: 'progress.md' },
 * ], 'status');
 * // result.value === 'implementing' (progress > spec-baseline)
 * ```
 */
export function resolveConflict(sources, fieldName) {
    // Filter to sources that have non-null values
    const withValues = sources.filter((s) => s.value !== null && s.value !== undefined);
    const consideredSources = sources.map((s) => ({
        priority: s.priority,
        label: s.label,
        hadValue: s.value !== null && s.value !== undefined,
    }));
    if (withValues.length === 0) {
        return null;
    }
    // Sort by priority rank (descending — highest priority first)
    const sorted = [...withValues].sort((a, b) => SOURCE_PRIORITY_RANK[b.priority] - SOURCE_PRIORITY_RANK[a.priority]);
    // Safe: sorted is non-empty because withValues is non-empty (checked above)
    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    const winner = sorted[0];
    // Determine if there was an actual conflict
    const hadConflict = withValues.length > 1 && withValues.some((s) => valuesAreDifferent(s.value, winner.value));
    // Build explanation
    const resolution = hadConflict
        ? buildConflictExplanation(fieldName, winner, sorted.slice(1))
        : `${fieldName}: used ${winner.label} (${winner.priority}), no conflict detected.`;
    return {
        value: winner.value,
        source: winner.priority,
        sourceLabel: winner.label,
        confidence: priorityToConfidence(winner.priority),
        resolution,
        hadConflict,
        consideredSources,
    };
}
/**
 * Build a human-readable explanation of how a conflict was resolved.
 */
function buildConflictExplanation(fieldName, winner, losers) {
    const loserDescriptions = losers
        .map((l) => `${l.label} (${l.priority}) = ${formatValue(l.value)}`)
        .join(', ');
    return (`${fieldName}: auto-resolved to ${formatValue(winner.value)} ` +
        `from ${winner.label} (${winner.priority}). ` +
        `Overrode: ${loserDescriptions}. ` +
        `Hierarchy: explicit > progress > wip > git-derived > spec-baseline.`);
}
/**
 * Format a value for display in resolution explanations.
 */
function formatValue(value) {
    if (value === null || value === undefined) {
        return 'null';
    }
    if (typeof value === 'string') {
        return `"${value}"`;
    }
    if (typeof value === 'number' || typeof value === 'boolean') {
        return String(value);
    }
    return JSON.stringify(value);
}
/**
 * Resolve multiple fields at once, returning a batch result.
 *
 * @param fieldSources - Map of field name to its data sources.
 * @returns Batch resolution with all fields resolved and a summary.
 */
export function resolveConflictBatch(fieldSources) {
    const fields = {};
    let conflictCount = 0;
    const resolutionLines = [];
    for (const [fieldName, sources] of Object.entries(fieldSources)) {
        const resolved = resolveConflict(sources, fieldName);
        if (resolved) {
            fields[fieldName] = resolved;
            if (resolved.hadConflict) {
                conflictCount++;
                resolutionLines.push(resolved.resolution);
            }
        }
    }
    const summary = conflictCount === 0
        ? 'No data conflicts detected.'
        : `Auto-resolved ${String(conflictCount)} conflict(s): ${resolutionLines.join(' | ')}`;
    return { fields, conflictCount, summary };
}
/**
 * Convenience: resolve a status conflict from common spec sources.
 * This is the most common use case — status appearing in multiple files.
 */
export function resolveStatusConflict(statusSources) {
    const sources = [];
    if (statusSources.explicit !== undefined) {
        sources.push({
            priority: 'explicit',
            value: statusSources.explicit,
            label: 'update_status tool',
        });
    }
    if (statusSources.progressMd !== undefined) {
        sources.push({
            priority: 'progress',
            value: statusSources.progressMd,
            label: 'progress.md',
        });
    }
    if (statusSources.wipTracker !== undefined) {
        sources.push({
            priority: 'wip',
            value: statusSources.wipTracker,
            label: 'WIP tracker',
        });
    }
    if (statusSources.gitDerived !== undefined) {
        sources.push({
            priority: 'git-derived',
            value: statusSources.gitDerived,
            label: 'git branch/commits',
        });
    }
    if (statusSources.specMd !== undefined) {
        sources.push({
            priority: 'spec-baseline',
            value: statusSources.specMd,
            label: 'spec.md',
        });
    }
    return resolveConflict(sources, 'status');
}
//# sourceMappingURL=source-resolver.js.map