import type { UpliftEvidenceSnapshot } from "@/domain/work-orders/api/work-order-uplifts-api"; import type { CreateWorkOrderUpliftInput, WorkOrderUplift, } from "@/domain/work-orders/types/work-order-uplift"; const POLL_INTERVAL_MS = 1000; const MAX_POLL_ATTEMPTS = 30; type CreateUpliftBody = { amount: number; notes: string; evidenceDocumentId?: number; evidenceDocumentIds?: number[]; }; export type SubmitWorkOrderUpliftDeps = { uploadEvidence: (workOrderId: string | number, file: File) => Promise; getEvidenceStatus: ( workOrderId: string | number, documentId: number, ) => Promise; create: (workOrderId: string | number, input: CreateUpliftBody) => Promise; sleep?: (ms: number) => Promise; }; function sleep(ms: number): Promise { return new Promise((resolve) => { setTimeout(resolve, ms); }); } function scanFailureMessage(scanStatus: "Rejected" | "Timeout"): string { if (scanStatus === "Rejected") { return "The evidence file was rejected by the security scan."; } return "The evidence file is still being scanned. Try again in a moment."; } async function waitForPassedScan( workOrderId: string | number, file: File, deps: SubmitWorkOrderUpliftDeps, ): Promise { const pause = deps.sleep ?? sleep; const uploaded = await deps.uploadEvidence(workOrderId, file); for (let attempt = 0; attempt < MAX_POLL_ATTEMPTS; attempt += 1) { const document = attempt === 0 ? uploaded : await deps.getEvidenceStatus(workOrderId, uploaded.id); if (document.scanStatus === "Passed") { return uploaded.id; } if (document.scanStatus === "Rejected") { throw new Error(scanFailureMessage("Rejected")); } await pause(POLL_INTERVAL_MS); } throw new Error(scanFailureMessage("Timeout")); } export async function submitWorkOrderUplift( workOrderId: string | number, input: CreateWorkOrderUpliftInput, deps: SubmitWorkOrderUpliftDeps, ): Promise { const evidenceDocumentIds: number[] = []; for (const file of input.files ?? []) { evidenceDocumentIds.push(await waitForPassedScan(workOrderId, file, deps)); } const [evidenceDocumentId] = evidenceDocumentIds; return deps.create(workOrderId, { amount: input.amount, notes: input.notes, evidenceDocumentId, evidenceDocumentIds: evidenceDocumentIds.length > 0 ? evidenceDocumentIds : undefined, }); }