export type BuildReviewProgressInput = { blocking: number; individualRequired: number; individualReviewed: number; groupRequired: number; reviewComplete: boolean; }; export type BuildReviewProgress = { blocking: number; individualRequired: number; individualReviewed: number; individualRemaining: number; groupRequired: number; groupReviewed: number; groupRemaining: number; required: number; reviewed: number; remaining: number; }; function count(value: number): number { return Number.isFinite(value) ? Math.max(0, Math.trunc(value)) : 0; } export function calculateBuildReviewProgress(input: BuildReviewProgressInput): BuildReviewProgress { const blocking = count(input.blocking); const individualRequired = count(input.individualRequired); const groupRequired = count(input.groupRequired); const individualReviewed = input.reviewComplete ? individualRequired : Math.min(individualRequired, count(input.individualReviewed)); const groupReviewed = input.reviewComplete ? groupRequired : 0; const individualRemaining = individualRequired - individualReviewed; const groupRemaining = groupRequired - groupReviewed; return { blocking, individualRequired, individualReviewed, individualRemaining, groupRequired, groupReviewed, groupRemaining, required: individualRequired + groupRequired, reviewed: individualReviewed + groupReviewed, remaining: individualRemaining + groupRemaining }; } /** Summary match counts describe inputs; they are not fresh review gates. */ export function attachmentDeliveryPreflight(input: { migrationRequired: boolean; hasBuild: boolean; reviewLoaded: boolean; blocking: number; remaining: number; inspectionComplete: boolean; missing: number; ambiguous: number; }): { state: "ready" | "warning" | "blocked" | "info"; detail: string } { if (input.migrationRequired) return { state: "blocked", detail: "i18n:govoplan-campaign.attachment_checks_await_mail_migration" }; if (!input.hasBuild) return { state: "info", detail: "i18n:govoplan-campaign.attachment_preflight_build_first" }; if (!input.reviewLoaded) return { state: "info", detail: "i18n:govoplan-campaign.attachment_preflight_loading" }; if (input.blocking > 0) return { state: "blocked", detail: "i18n:govoplan-campaign.attachment_preflight_blocked" }; if (input.inspectionComplete || input.remaining === 0) { return { state: "ready", detail: "i18n:govoplan-campaign.attachment_preflight_satisfied" }; } if (input.missing + input.ambiguous > 0) { return { state: "warning", detail: "i18n:govoplan-campaign.attachment_preflight_review" }; } return { state: "info", detail: "i18n:govoplan-campaign.attachment_preflight_pending" }; }