/** Human-readable duration from milliseconds.
 *  `420 → "420ms"`, `6100 → "6.1s"`, `62000 → "1m 02s"`, `null → "—"`. */
export function fmtDuration(ms: number | null | undefined): string {
    if (ms == null) return '—';
    if (ms < 1000) return `${Math.round(ms)}ms`;
    const secs = ms / 1000;
    if (secs < 60) return `${secs.toFixed(secs < 10 ? 1 : 0)}s`;
    // Round to whole seconds *before* splitting so e.g. 119_600ms renders
    // "2m 00s", not "1m 60s".
    const whole = Math.round(secs);
    const mins = Math.floor(whole / 60);
    const rem = whole % 60;
    return `${mins}m ${String(rem).padStart(2, '0')}s`;
}

/** Relative "time ago" from an ISO timestamp, falling back to a locale date
 *  once it's more than a day old. `now` is injectable for tests. */
export function fmtAgo(iso: string, now: number = Date.now()): string {
    const then = new Date(iso).getTime();
    const secs = Math.round((now - then) / 1000);
    if (secs < 45) return 'just now';
    if (secs < 90) return '1m ago';
    const mins = Math.round(secs / 60);
    if (mins < 60) return `${mins}m ago`;
    const hrs = Math.round(mins / 60);
    if (hrs < 24) return `${hrs}h ago`;
    return new Date(iso).toLocaleDateString();
}
