import { CAMPAIGN_RECURRENCES, CAMPAIGN_STATUSES } from "./campaign-form"; export type CampaignRecurrence = (typeof CAMPAIGN_RECURRENCES)[number]; export type CampaignStatus = (typeof CAMPAIGN_STATUSES)[number]; export type CampaignFormRecurrenceInput = { recurrence: CampaignRecurrence | (string & {}); status: CampaignStatus; lastRunAt?: number | null; now?: number; }; export type CampaignRunInfo = { campaignStatus: CampaignStatus; agentRuns?: Array<{ status: string; updatedAt?: number; }>; }; export function isAllowedCampaignRecurrence(value: string): boolean { return CAMPAIGN_RECURRENCES.includes(value as CampaignRecurrence); } function addDaysUTC(base: number, days: number): number { const date = new Date(base); return Date.UTC( date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate() + days, date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(), date.getUTCMilliseconds(), ); } function addMonthsUTC(base: number, months: number): number { const date = new Date(base); return Date.UTC( date.getUTCFullYear(), date.getUTCMonth() + months, date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(), date.getUTCMilliseconds(), ); } export function calculateNextRunAt(input: CampaignFormRecurrenceInput): number | null { if (input.status !== "active") { return null; } if (!isAllowedCampaignRecurrence(input.recurrence)) { return null; } if (input.recurrence === "manual") { return null; } const anchor = input.lastRunAt ?? input.now ?? Date.now(); if (input.recurrence === "daily") { return addDaysUTC(anchor, 1); } if (input.recurrence === "weekly") { return addDaysUTC(anchor, 7); } return addMonthsUTC(anchor, 1); } export function getCampaignCurrentRunStatus(input: CampaignRunInfo): string { const agentRuns = input.agentRuns ?? []; if (agentRuns.length > 0) { const ordered = [...agentRuns].sort((a, b) => { const aUpdatedAt = typeof a.updatedAt === "number" ? a.updatedAt : 0; const bUpdatedAt = typeof b.updatedAt === "number" ? b.updatedAt : 0; return bUpdatedAt - aUpdatedAt; }); const latestStatus = ordered.at(0)?.status; if (latestStatus === "running") { return "running"; } if (latestStatus === "pending") { return "pending"; } if ( latestStatus === "succeeded" || latestStatus === "failed" || latestStatus === "canceled" ) { return latestStatus; } } return input.campaignStatus === "paused" ? "paused" : "idle"; }