/**
 * Pure derivations for the business workspace's **ranked at-risk list** — turning a model's per-record
 * scoring results (`MJ: Process Run Details` payloads) into a "who to focus on" list sorted by risk, and
 * the model's global feature importance into plain-language "what's driving this" drivers.
 *
 * Honest about the gap: MJ stores only GLOBAL feature importance (not per-record/SHAP), so we surface the
 * top global drivers once for the whole prediction rather than fabricating per-member attribution.
 *
 * Framework-free + deterministic → unit-tested with no Angular.
 */
function bandFor(score) {
    return score >= 0.7 ? 'high' : score >= 0.4 ? 'medium' : 'low';
}
/** Parse + rank the per-record predictions into the at-risk list (highest risk first). */
export function parseAtRiskRows(details) {
    const rows = [];
    for (const d of details) {
        if (!d.ResultPayload)
            continue;
        let parsed;
        try {
            parsed = JSON.parse(d.ResultPayload);
        }
        catch {
            continue;
        }
        // Write-back runs nest the prediction under `output`; generic runs carry it at the top level.
        const p = parsed.output ?? parsed;
        if (typeof p.score !== 'number' || !Number.isFinite(p.score))
            continue;
        const score = p.score;
        rows.push({ recordId: d.recordId, score, riskPct: Math.round(score * 100), class: p.class ?? null, band: bandFor(score) });
    }
    return rows.sort((a, b) => b.score - a.score);
}
/**
 * The top plain-language drivers for the whole prediction, from the model's global feature importance.
 * Accepts the object form (`{"MembershipType=Student": 0.9, ...}`) or the array form
 * (`[{feature, importance}]`), strips one-hot `=value` suffixes, de-duplicates, and returns the
 * highest-importance feature names — so a business user sees "what's driving this", not raw weights.
 */
export function topGlobalDrivers(featureImportanceJson, n = 3) {
    if (!featureImportanceJson)
        return [];
    let parsed;
    try {
        parsed = JSON.parse(featureImportanceJson);
    }
    catch {
        return [];
    }
    const pairs = [];
    if (Array.isArray(parsed)) {
        for (const e of parsed) {
            const name = (e.feature ?? e.name);
            const weight = (e.importance ?? e.value);
            if (typeof name === 'string' && typeof weight === 'number')
                pairs.push({ name, weight: Math.abs(weight) });
        }
    }
    else if (parsed && typeof parsed === 'object') {
        for (const [name, weight] of Object.entries(parsed)) {
            if (typeof weight === 'number')
                pairs.push({ name, weight: Math.abs(weight) });
        }
    }
    // Collapse one-hot columns ("Feature=Value" → "Feature"), keeping each feature's max weight.
    const byFeature = new Map();
    for (const { name, weight } of pairs) {
        const base = name.split('=')[0].trim();
        if (!base)
            continue;
        byFeature.set(base, Math.max(byFeature.get(base) ?? 0, weight));
    }
    return [...byFeature.entries()].sort((a, b) => b[1] - a[1]).slice(0, n).map(([name]) => name);
}
//# sourceMappingURL=at-risk.view-models.js.map