"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SimilarityEngine = void 0;
const LANG_WEIGHT = 0.35;
const FW_WEIGHT = 0.25;
const BEHAVIOR_WEIGHT = 0.25;
const OUTCOME_WEIGHT = 0.15;
function weightedJaccard(a, b) {
    const allKeys = new Set([...Object.keys(a), ...Object.keys(b)]);
    if (allKeys.size === 0)
        return 0;
    let intersection = 0;
    let union = 0;
    for (const key of allKeys) {
        const va = a[key] || 0;
        const vb = b[key] || 0;
        intersection += Math.min(va, vb);
        union += Math.max(va, vb);
    }
    return intersection / union;
}
function scalarSimilarity(a, b) {
    return 1 - Math.abs(a - b);
}
function computeSimilarity(a, b) {
    const langSim = weightedJaccard(a.languages, b.languages);
    const fwSim = weightedJaccard(a.frameworks, b.frameworks);
    const behaviorSim = scalarSimilarity(a.patternAcceptanceRate, b.patternAcceptanceRate);
    const outcomeSim = scalarSimilarity(a.successRate, b.successRate);
    const score = langSim * LANG_WEIGHT +
        fwSim * FW_WEIGHT +
        behaviorSim * BEHAVIOR_WEIGHT +
        outcomeSim * OUTCOME_WEIGHT;
    const commonLanguages = Object.keys(a.languages).filter((l) => b.languages[l]);
    const commonFrameworks = Object.keys(a.frameworks).filter((f) => b.frameworks[f]);
    return {
        developerId: b.developerId,
        score: Math.round(score * 10000) / 10000,
        commonLanguages,
        commonFrameworks,
    };
}
class SimilarityEngine {
    cache = new Map();
    cacheTTL = 60_000;
    findSimilar(developerId, profiles, limit = 30) {
        const cached = this.cache.get(developerId);
        if (cached && Date.now() - cached.timestamp < this.cacheTTL) {
            return cached.results.slice(0, limit);
        }
        const target = profiles.get(developerId);
        if (!target)
            return [];
        const results = [];
        for (const [id, profile] of profiles) {
            if (id === developerId)
                continue;
            results.push(computeSimilarity(target, profile));
        }
        results.sort((a, b) => b.score - a.score);
        this.cache.set(developerId, { results, timestamp: Date.now() });
        return results.slice(0, limit);
    }
    invalidateCache(developerId) {
        if (developerId) {
            this.cache.delete(developerId);
        }
        else {
            this.cache.clear();
        }
    }
}
exports.SimilarityEngine = SimilarityEngine;
//# sourceMappingURL=similarity-engine.js.map