import type { SequenceProgress } from './types' /** @deprecated Scheduled for removal in MINT 1.4; instrument monitor helpers move to the mld-ms plugins. */ export function sequenceProgressPercent(progress: SequenceProgress | null | undefined): number { if (!progress || progress.total_samples <= 0) return 0 return Math.round(clamp((progress.current_sample / progress.total_samples) * 100, 0, 100)) } /** @deprecated Scheduled for removal in MINT 1.4; instrument monitor helpers move to the mld-ms plugins. */ export function sequenceSamplesRemaining(progress: SequenceProgress | null | undefined): number { if (!progress) return 0 return Math.max(0, progress.total_samples - progress.current_sample) } /** @deprecated Scheduled for removal in MINT 1.4; instrument monitor helpers move to the mld-ms plugins. */ export function estimateSequenceRemainingSeconds( progress: SequenceProgress | null | undefined, ): number | null { if (!progress) return null const samplesLeft = sequenceSamplesRemaining(progress) if (samplesLeft <= 0) return 0 const explicit = progress.estimated_remaining_seconds if (typeof explicit === 'number' && explicit > 0) return explicit const avg = progress.avg_sample_seconds ?? average(progress.sample_durations) if (typeof avg === 'number' && avg > 0) return samplesLeft * avg const elapsed = progress.elapsed_seconds ?? 0 if (elapsed > 0 && progress.current_sample > 0) { return (elapsed / progress.current_sample) * samplesLeft } return null } /** @deprecated Scheduled for removal in MINT 1.4; instrument monitor helpers move to the mld-ms plugins. */ export function estimateSequenceFinishDate( progress: SequenceProgress | null | undefined, now = new Date(), ): Date | null { if (!progress) return null const explicit = coerceDate(progress.estimated_finish_time) if (explicit) return explicit const remaining = estimateSequenceRemainingSeconds(progress) if (remaining == null || remaining <= 0) return null return new Date(now.getTime() + remaining * 1000) } /** @deprecated Scheduled for removal in MINT 1.4; instrument monitor helpers move to the mld-ms plugins. */ export function formatSequenceRemaining(progress: SequenceProgress | null | undefined): string | null { const remaining = estimateSequenceRemainingSeconds(progress) if (remaining == null || remaining <= 0) return null const minutes = remaining / 60 if (minutes < 1) return `${Math.round(remaining)}s left` if (minutes < 60) return `~${Math.round(minutes)}m left` const hours = Math.floor(minutes / 60) const mins = Math.round(minutes % 60) return mins > 0 ? `~${hours}h ${mins}m left` : `~${hours}h left` } /** @deprecated Scheduled for removal in MINT 1.4; instrument monitor helpers move to the mld-ms plugins. */ export function formatSequenceEta( progress: SequenceProgress | null | undefined, locale?: Intl.LocalesArgument, options: Intl.DateTimeFormatOptions = {}, ): string | null { const finish = estimateSequenceFinishDate(progress) if (!finish) return null return finish.toLocaleTimeString(locale, { hour: '2-digit', minute: '2-digit', ...options, }) } function average(values: readonly number[] | undefined): number | null { if (!values?.length) return null const usable = values.filter(value => Number.isFinite(value) && value >= 0) if (usable.length === 0) return null return usable.reduce((sum, value) => sum + value, 0) / usable.length } function coerceDate(value: string | Date | null | undefined): Date | null { if (!value) return null const date = value instanceof Date ? value : new Date(value) return Number.isNaN(date.getTime()) ? null : date } function clamp(value: number, min: number, max: number): number { return Math.min(max, Math.max(min, value)) }