import type { BoxBrainAvailability } from './types'; export type RandomSource = () => number; export interface TypingDelayOptions { rng?: RandomSource | undefined; minSecondsPerCharacter?: number | undefined; maxSecondsPerCharacter?: number | undefined; } export interface ReplyDelayOptions { isFirstReplyInExchange: boolean; rng?: RandomSource | undefined; onlineMinSeconds?: number | undefined; onlineMaxSeconds?: number | undefined; dndReplyProbability?: number | undefined; dndMinSeconds?: number | undefined; dndMaxSeconds?: number | undefined; } export const ONLINE_AVAILABILITY: BoxBrainAvailability = { mode: 'online' }; export const DND_AVAILABILITY: BoxBrainAvailability = { mode: 'do_not_disturb' }; export const OFFLINE_AVAILABILITY: BoxBrainAvailability = { mode: 'offline' }; export function createTypingDelay(message: string, options: TypingDelayOptions = {}): number { if (message.length === 0) { return 0; } const rng = options.rng ?? Math.random; const min = options.minSecondsPerCharacter ?? 0.05; const max = options.maxSecondsPerCharacter ?? 0.08; const secondsPerCharacter = interpolate(min, max, clampUnit(rng())); return roundSeconds(message.length * secondsPerCharacter); } export function createReplyDelay( availability: BoxBrainAvailability, options: ReplyDelayOptions, ): number | null { if (availability.mode === 'offline') { return null; } if (!options.isFirstReplyInExchange) { return 0; } const rng = options.rng ?? Math.random; if (availability.mode === 'do_not_disturb') { const probability = options.dndReplyProbability ?? 0.2; if (clampUnit(rng()) > probability) { return null; } return roundSeconds(interpolate(options.dndMinSeconds ?? 60, options.dndMaxSeconds ?? 600, clampUnit(rng()))); } return roundSeconds(interpolate(options.onlineMinSeconds ?? 1, options.onlineMaxSeconds ?? 12, clampUnit(rng()))); } function interpolate(min: number, max: number, ratio: number): number { return min + (max - min) * ratio; } function clampUnit(value: number): number { if (Number.isNaN(value)) { return 0; } return Math.min(1, Math.max(0, value)); } function roundSeconds(value: number): number { return Math.round(value * 1_000_000) / 1_000_000; }