import type { CampaignRecoveryChannel } from "../../../api/deliveryRecovery"; import { asRecord } from "../utils/campaignView"; export type ReportReconciliation = { jobId: string; kind: "outcome"; decision: "smtp_accepted" | "not_sent" | "imap_appended" | "imap_not_appended"; } | { jobId: string; kind: "claim"; channel: CampaignRecoveryChannel; revision: string; }; export function reportClaimRecovery(row: Record, channel: CampaignRecoveryChannel): { eligible: boolean; revision: string } { const metadata = asRecord(asRecord(row.recovery)[channel]); const revision = typeof metadata.revision === "string" ? metadata.revision : ""; const state = String(channel === "smtp" ? row.send_status ?? "" : row.imap_status ?? ""); return { eligible: metadata.eligible === true && Boolean(revision) && (channel === "smtp" ? ["claimed", "sending"].includes(state) : state === "appending"), revision }; } export function reportRetryableFailure(row: Record): boolean { return ["failed_temporary", "failed_permanent", "partially_accepted"].includes(String(row.send_status ?? "")); } export function reportUnattempted(row: Record): boolean { return ["not_queued", "cancelled", "queued"].includes(String(row.send_status ?? "")) && Number(row.attempt_count ?? 0) === 0 && Number(row.postbox_attempt_count ?? 0) === 0 && Number(row.print_attempt_count ?? 0) === 0 && row.build_status === "built" && ["ready", "warning", "needs_review"].includes(String(row.validation_status ?? "")); } export function reportRecoveryHints(row: Record): string[] { const activeChannels = [ ...(["claimed", "sending"].includes(String(row.send_status ?? "")) ? ["smtp"] : []), ...(row.imap_status === "appending" ? ["imap"] : []) ]; return [...new Set(activeChannels.flatMap(channel => { const metadata = asRecord(asRecord(row.recovery)[channel]); if (metadata.eligible === true) return []; return [metadata.reason === "live_claim" ? "i18n:govoplan-campaign.report_claim_still_active" : "i18n:govoplan-campaign.report_claim_owner_unconfirmed"]; }))]; }