/**
 * 404 recovery suggestions — pure heuristic matching of a dead path to the
 * best live URL using path-segment + title token similarity. Used as the
 * always-available baseline; the API can layer AI ranking on top when a
 * provider is configured.
 */
function tokens(input) {
    return input
        .toLowerCase()
        .replace(/^https?:\/\/[^/]+/i, '')
        .replace(/[^a-z0-9]+/g, ' ')
        .split(/\s+/)
        .filter((t) => t.length > 1);
}
function jaccard(a, b) {
    if (a.size === 0 && b.size === 0)
        return 0;
    let inter = 0;
    for (const x of a)
        if (b.has(x))
            inter++;
    const union = a.size + b.size - inter;
    return union === 0 ? 0 : inter / union;
}
/**
 * Suggest the best redirect target for a dead `fromPath`. Returns null when no
 * candidate clears the minimum confidence threshold (default 30).
 */
export function suggestRedirectTarget(fromPath, candidates, minConfidence = 30) {
    const fromTokens = new Set(tokens(fromPath));
    if (fromTokens.size === 0 || candidates.length === 0)
        return null;
    let best = null;
    for (const c of candidates) {
        const pathTokens = new Set(tokens(c.url));
        const titleTokens = new Set(tokens(c.title ?? ''));
        const pathSim = jaccard(fromTokens, pathTokens);
        const titleSim = jaccard(fromTokens, titleTokens);
        // Path match weighted higher than title match.
        const score = Math.round((pathSim * 0.7 + titleSim * 0.3) * 100);
        if (!best || score > best.confidence) {
            best = {
                toPath: c.url,
                confidence: score,
                reason: pathSim >= titleSim
                    ? `URL path similarity to ${c.url}`
                    : `Title similarity to "${c.title ?? c.url}"`,
            };
        }
    }
    if (!best || best.confidence < minConfidence)
        return null;
    return best;
}
//# sourceMappingURL=suggest.js.map