import type { ApiSettings, CampaignListItem } from "../types"; import { apiFetch } from "./client"; export type CampaignListResponse = | CampaignListItem[] | { campaigns?: CampaignListItem[]; items?: CampaignListItem[]; results?: CampaignListItem[]; }; export type CampaignUpdatePayload = { external_id?: string | null; name?: string | null; status?: string | null; description?: string | null; }; export type CampaignCreateMinimalPayload = { external_id?: string; name?: string; description?: string | null; current_flow?: string; current_step?: string; }; export type CampaignCreateResponse = { campaign: CampaignListItem & { current_version_id?: string | null; }; version: CampaignVersionListItem; }; export type CampaignVersionListItem = { id: string; campaign_id: string; version_number: number; schema_version?: string; source_filename?: string | null; source_base_path?: string | null; workflow_state?: string; current_flow?: string; current_step?: string | null; is_complete?: boolean; editor_state?: Record; autosaved_at?: string | null; published_at?: string | null; locked_at?: string | null; locked_by_user_id?: string | null; user_lock_state?: "temporary" | "permanent" | null; user_locked_at?: string | null; user_locked_by_user_id?: string | null; created_at?: string; updated_at?: string; validation_summary?: Record | null; build_summary?: Record | null; }; export type CampaignVersionDetail = CampaignVersionListItem & { raw_json: Record; campaign_json?: Record; }; export type CampaignVersionUpdatePayload = { campaign_json?: Record | null; current_flow?: string | null; current_step?: string | null; workflow_state?: string | null; is_complete?: boolean | null; editor_state?: Record | null; source_filename?: string | null; source_base_path?: string | null; }; export type CampaignPartialValidationPayload = { campaign_json?: Record | null; section?: string | null; }; export type CampaignPartialValidationResponse = { ok: boolean; section?: string | null; error_count: number; warning_count: number; info_count: number; issues: Record[]; }; export type CampaignSummary = { generated_at?: string; campaign?: CampaignListItem; current_version?: { id: string; version_number?: number; schema_version?: string; source_filename?: string | null; created_at?: string | null; validation_summary?: Record | null; build_summary?: Record | null; } | null; cards?: { jobs_total?: number; queueable?: number; needs_attention?: number; sent?: number; failed?: number; imap_appended?: number; imap_failed?: number; }; status_counts?: Record>; issues?: Record; attachments?: Record; attempts?: Record; delivery?: Record; recent_failures?: Record[]; }; export type CampaignQueuePayload = { version_id?: string | null; include_warnings?: boolean; enqueue_celery?: boolean; dry_run?: boolean; }; export type CampaignSendNowPayload = { version_id?: string | null; include_warnings?: boolean; check_files?: boolean; validate_before_send?: boolean; build_before_send?: boolean; dry_run?: boolean; use_rate_limit?: boolean; enqueue_imap_task?: boolean; }; export type CampaignAttachmentPreviewFile = { id: string; version_id?: string; blob_id?: string; display_path: string; filename: string; owner_type: string; owner_id: string; checksum_sha256?: string; size_bytes?: number; content_type?: string | null; }; export type CampaignAttachmentPreviewRule = { source: "global" | "entry"; entry_index: number; entry_id?: string | null; index: number; attachment_id?: string | null; label?: string | null; required: boolean; pattern: string; base_path_name?: string | null; base_path?: string | null; status: "ok" | "missing" | "ambiguous"; behavior?: string | null; matches: CampaignAttachmentPreviewFile[]; match_count: number; issues: Record[]; }; export type CampaignAttachmentPreviewResponse = { campaign_id: string; version_id: string; shared_file_count: number; rules: CampaignAttachmentPreviewRule[]; unused_shared_files: CampaignAttachmentPreviewFile[]; }; export type CampaignAttachmentPreviewPayload = { include_unmatched?: boolean; campaign_json?: Record; }; export type CampaignMockSendPayload = { version_id?: string | null; send?: boolean; include_warnings?: boolean; include_needs_review?: boolean; append_sent?: boolean; clear_mailbox?: boolean; check_files?: boolean; }; export type CampaignReviewStatePayload = { inspection_complete: boolean; reviewed_message_keys: string[]; }; export async function listCampaigns(settings: ApiSettings): Promise { const response = await apiFetch(settings, "/api/v1/campaigns"); if (Array.isArray(response)) { return response; } return response.campaigns ?? response.items ?? response.results ?? []; } export async function getCampaign(settings: ApiSettings, campaignId: string): Promise { return apiFetch(settings, `/api/v1/campaigns/${campaignId}`); } export async function updateCampaignMetadata( settings: ApiSettings, campaignId: string, payload: CampaignUpdatePayload ): Promise { return apiFetch(settings, `/api/v1/campaigns/${campaignId}`, { method: "PUT", body: JSON.stringify(payload) }); } export async function createNewCampaign( settings: ApiSettings, overrides: CampaignCreateMinimalPayload = {} ): Promise { const now = new Date(); const stamp = now.toISOString().slice(0, 19).replace(/[-:T]/g, ""); const payload = { external_id: overrides.external_id ?? `new-campaign-${stamp}`, name: overrides.name ?? "New Campaign", description: overrides.description ?? "", current_flow: overrides.current_flow ?? "create", current_step: overrides.current_step ?? "basics" }; return apiFetch(settings, "/api/v1/campaigns/new", { method: "POST", body: JSON.stringify(payload) }); } export async function getCampaignSchema(settings: ApiSettings): Promise { return apiFetch(settings, "/api/v1/schemas/campaign"); } export async function listCampaignVersions( settings: ApiSettings, campaignId: string ): Promise { return apiFetch(settings, `/api/v1/campaigns/${campaignId}/versions`); } export async function getCampaignVersion( settings: ApiSettings, campaignId: string, versionId: string ): Promise { return apiFetch(settings, `/api/v1/campaigns/${campaignId}/versions/${versionId}`); } export async function unlockCampaignVersionValidation( settings: ApiSettings, campaignId: string, versionId: string ): Promise { return apiFetch(settings, `/api/v1/campaigns/${campaignId}/versions/${versionId}/unlock-validation`, { method: "POST" }); } export async function lockCampaignVersionTemporarily( settings: ApiSettings, campaignId: string, versionId: string ): Promise { return apiFetch(settings, `/api/v1/campaigns/${campaignId}/versions/${versionId}/lock-temporarily`, { method: "POST" }); } export async function unlockCampaignVersionUserLock( settings: ApiSettings, campaignId: string, versionId: string ): Promise { return apiFetch(settings, `/api/v1/campaigns/${campaignId}/versions/${versionId}/unlock-user-lock`, { method: "POST" }); } export async function lockCampaignVersionPermanently( settings: ApiSettings, campaignId: string, versionId: string ): Promise { return apiFetch(settings, `/api/v1/campaigns/${campaignId}/versions/${versionId}/lock-permanently`, { method: "POST" }); } export async function updateCampaignVersion( settings: ApiSettings, campaignId: string, versionId: string, payload: CampaignVersionUpdatePayload ): Promise { return apiFetch(settings, `/api/v1/campaigns/${campaignId}/versions/${versionId}`, { method: "PUT", body: JSON.stringify(payload) }); } export async function forkCampaignVersion( settings: ApiSettings, campaignId: string, versionId: string, payload: CampaignVersionUpdatePayload = {} ): Promise { return apiFetch(settings, `/api/v1/campaigns/${campaignId}/versions/${versionId}/fork`, { method: "POST", body: JSON.stringify(payload) }); } export async function autosaveCampaignVersion( settings: ApiSettings, campaignId: string, versionId: string, payload: CampaignVersionUpdatePayload ): Promise { return apiFetch(settings, `/api/v1/campaigns/${campaignId}/versions/${versionId}/autosave`, { method: "POST", body: JSON.stringify(payload) }); } export async function setCampaignVersionStep( settings: ApiSettings, campaignId: string, versionId: string, currentStep: string, currentFlow?: string | null ): Promise { return apiFetch(settings, `/api/v1/campaigns/${campaignId}/versions/${versionId}/set-step`, { method: "POST", body: JSON.stringify({ current_flow: currentFlow, current_step: currentStep }) }); } export async function validatePartial( settings: ApiSettings, campaignId: string, versionId: string, payload: CampaignPartialValidationPayload = {} ): Promise { return apiFetch(settings, `/api/v1/campaigns/${campaignId}/versions/${versionId}/validate-partial`, { method: "POST", body: JSON.stringify(payload) }); } export async function publishCampaignVersion( settings: ApiSettings, campaignId: string, versionId: string ): Promise { return apiFetch(settings, `/api/v1/campaigns/${campaignId}/versions/${versionId}/publish`, { method: "POST" }); } export async function validateVersion( settings: ApiSettings, versionId: string, checkFiles = false ): Promise> { return apiFetch>(settings, `/api/v1/campaigns/versions/${versionId}/validate`, { method: "POST", body: JSON.stringify({ check_files: checkFiles }) }); } export async function buildVersion( settings: ApiSettings, versionId: string, writeEml = true ): Promise> { return apiFetch>(settings, `/api/v1/campaigns/versions/${versionId}/build`, { method: "POST", body: JSON.stringify({ write_eml: writeEml }) }); } export function previewCampaignAttachments( settings: ApiSettings, campaignId: string, versionId: string, payload: CampaignAttachmentPreviewPayload = {} ): Promise { return apiFetch( settings, `/api/v1/campaigns/${campaignId}/versions/${versionId}/attachments/preview`, { method: "POST", body: JSON.stringify(payload) } ); } export async function getCampaignSummary(settings: ApiSettings, campaignId: string): Promise { return apiFetch(settings, `/api/v1/campaigns/${campaignId}/summary`); } export async function getCampaignJobs( settings: ApiSettings, campaignId: string, versionId?: string ): Promise<{ jobs: Record[] }> { const suffix = versionId ? `?version_id=${encodeURIComponent(versionId)}` : ""; return apiFetch<{ jobs: Record[] }>(settings, `/api/v1/campaigns/${campaignId}/jobs${suffix}`); } export async function updateCampaignReviewState( settings: ApiSettings, campaignId: string, versionId: string, payload: CampaignReviewStatePayload ): Promise { return apiFetch(settings, `/api/v1/campaigns/${campaignId}/versions/${versionId}/review-state`, { method: "POST", body: JSON.stringify(payload) }); } export async function queueCampaign( settings: ApiSettings, campaignId: string, payload: CampaignQueuePayload = {} ): Promise> { return apiFetch>(settings, `/api/v1/campaigns/${campaignId}/queue`, { method: "POST", body: JSON.stringify(payload) }); } export async function sendCampaignNow( settings: ApiSettings, campaignId: string, payload: CampaignSendNowPayload = {} ): Promise> { return apiFetch>(settings, `/api/v1/campaigns/${campaignId}/send-now`, { method: "POST", body: JSON.stringify(payload) }); } export async function mockSendCampaign( settings: ApiSettings, campaignId: string, payload: CampaignMockSendPayload = {} ): Promise> { return apiFetch>(settings, `/api/v1/campaigns/${campaignId}/mock-send`, { method: "POST", body: JSON.stringify(payload) }); } export async function pauseCampaign(settings: ApiSettings, campaignId: string): Promise> { return apiFetch>(settings, `/api/v1/campaigns/${campaignId}/pause`, { method: "POST" }); } export async function resumeCampaign(settings: ApiSettings, campaignId: string): Promise> { return apiFetch>(settings, `/api/v1/campaigns/${campaignId}/resume`, { method: "POST" }); } export async function cancelCampaign(settings: ApiSettings, campaignId: string): Promise> { return apiFetch>(settings, `/api/v1/campaigns/${campaignId}/cancel`, { method: "POST" }); } export async function appendSent( settings: ApiSettings, campaignId: string, dryRun = false ): Promise> { return apiFetch>(settings, `/api/v1/campaigns/${campaignId}/append-sent`, { method: "POST", body: JSON.stringify({ dry_run: dryRun }) }); }