// engine/discovery/result-ranker.ts — SPEC-181
// Ranks and deduplicates npm + GitHub discovery results by popularity and stack relevance.
const MAX_RESULTS = 10;
const MAX_SCORE = 50;
function scoreNpm(tool) {
    if (!tool.weeklyDownloads || tool.weeklyDownloads <= 0) {
        return 0;
    }
    return Math.min(Math.log10(tool.weeklyDownloads) * 10, MAX_SCORE);
}
function scoreGithub(tool) {
    if (!tool.stars || tool.stars <= 0) {
        return 0;
    }
    return Math.min(Math.log10(tool.stars) * 15, MAX_SCORE);
}
function stackBonus(tool, stackLanguage) {
    if (!stackLanguage) {
        return 0;
    }
    const lang = stackLanguage.toLowerCase();
    const text = `${tool.name} ${tool.description}`.toLowerCase();
    return text.includes(lang) ? 10 : 0;
}
function computeScore(tool, stackLanguage) {
    const base = tool.source === 'npm' ? scoreNpm(tool) : scoreGithub(tool);
    return base + stackBonus(tool, stackLanguage);
}
/**
 * Ranks npm and GitHub discovery results by popularity and stack relevance.
 * Deduplicates by name (case-insensitive), returns top 10 sorted descending by score.
 */
export function rankResults(npmResults, githubResults, stackLanguage) {
    const seen = new Map();
    for (const tool of [...npmResults, ...githubResults]) {
        const key = tool.name.toLowerCase();
        const computedScore = computeScore(tool, stackLanguage);
        const scored = { ...tool, score: computedScore };
        const existing = seen.get(key);
        if (!existing || computedScore > (existing.score ?? 0)) {
            seen.set(key, scored);
        }
    }
    return [...seen.values()].sort((a, b) => (b.score ?? 0) - (a.score ?? 0)).slice(0, MAX_RESULTS);
}
//# sourceMappingURL=result-ranker.js.map