function hostOf(value) {
    if (!value)
        return null;
    try {
        return new URL(value).hostname.toLowerCase();
    }
    catch {
        return null;
    }
}
function normalizeHost(domain) {
    return domain
        .trim()
        .toLowerCase()
        .replace(/^https?:\/\//, '')
        .replace(/\/.*$/, '')
        .replace(/^\*\./, '');
}
/** Concatenate user-supplied string values for keyword scanning. */
function textBlob(fields, rawValues) {
    const parts = [];
    for (const field of fields) {
        if (field.type === 'honeypot' || field.type === 'divider')
            continue;
        const v = rawValues[field.key];
        if (typeof v === 'string')
            parts.push(v);
        else if (Array.isArray(v))
            parts.push(v.map((x) => String(x)).join(' '));
    }
    return parts.join(' \n ').toLowerCase();
}
export function scoreSubmissionSpam(input) {
    const reasons = [];
    const settings = input.settings ?? {};
    const strategies = new Set([
        ...(input.defaultStrategies ?? []),
        ...(settings.strategies ?? []),
    ]);
    // Honeypot — always evaluated when a honeypot field/key exists. A populated
    // honeypot means an automated client filled a field that is hidden from
    // humans via CSS.
    const honeypotKey = settings.honeypotFieldKey ?? input.fields.find((f) => f.type === 'honeypot')?.key;
    if (honeypotKey) {
        const v = input.rawValues[honeypotKey];
        const filled = typeof v === 'string' ? v.trim() !== '' : v != null && v !== false;
        if (filled)
            reasons.push('honeypot');
    }
    // Time-to-submit — humans take a few seconds; instant submits are bots.
    if (strategies.has('timeToSubmit') &&
        typeof settings.minSubmitSeconds === 'number' &&
        settings.minSubmitSeconds > 0 &&
        typeof input.elapsedMs === 'number' &&
        input.elapsedMs >= 0) {
        if (input.elapsedMs < settings.minSubmitSeconds * 1000)
            reasons.push('too_fast');
    }
    // Email / domain blocklist.
    if (strategies.has('blocklist')) {
        const email = (input.senderEmail ?? '').trim().toLowerCase();
        if (email) {
            const blockedEmails = (settings.blockedEmails ?? []).map((e) => e.trim().toLowerCase());
            if (blockedEmails.includes(email))
                reasons.push('blocked_email');
            const domain = email.split('@')[1] ?? '';
            const blockedDomains = (settings.blockedDomains ?? []).map((d) => normalizeHost(d));
            if (domain && blockedDomains.includes(domain))
                reasons.push('blocked_domain');
        }
    }
    // Keyword blocklist.
    if (strategies.has('keyword') && (settings.blockedKeywords?.length ?? 0) > 0) {
        const blob = textBlob(input.fields, input.rawValues);
        for (const keyword of settings.blockedKeywords ?? []) {
            const k = keyword.trim().toLowerCase();
            if (k && blob.includes(k)) {
                reasons.push('blocked_keyword');
                break;
            }
        }
    }
    // Domain allowlist — the submitting origin must be on the allowlist.
    if (strategies.has('domainAllowlist') && (settings.allowedDomains?.length ?? 0) > 0) {
        const host = hostOf(input.origin) ?? hostOf(input.referrer);
        const allowed = (settings.allowedDomains ?? []).map((d) => normalizeHost(d));
        const ok = host != null && allowed.some((a) => host === a || host.endsWith(`.${a}`));
        if (!ok)
            reasons.push('origin_not_allowed');
    }
    return { status: reasons.length > 0 ? 'spam' : 'clean', reasons };
}
//# sourceMappingURL=spam.js.map