import { apiFetch, apiPath, type ApiSettings } from "@govoplan/core-webui"; export type TicketSubject = { kind: string; id: string; label?: string | null; role?: string | null; }; export type TicketLink = { link_id: string; kind: string; owner_module: string; resource_type: string; resource_id: string; relation: string; label?: string | null; url?: string | null; metadata: Record; }; export type TicketRecord = { tenant_id: string; ticket_id: string; ticket_number: string; revision: number; ticket_type: "request" | "incident" | "problem" | "report"; priority: "low" | "normal" | "high" | "urgent"; status: string; title: string; description: string; visibility: "tenant" | "restricted"; queue_ref?: string | null; assignee?: TicketSubject | null; reporter?: TicketSubject | null; requester?: TicketSubject | null; participants: TicketSubject[]; links: TicketLink[]; service_target_at?: string | null; received_at: string; recorded_at: string; resolved_at?: string | null; resolution_summary?: string | null; deleted_at?: string | null; change_reason: string; metadata: Record; }; export type TicketListResponse = { tickets: TicketRecord[]; total: number; offset: number; limit: number; }; export type TicketAvailability = { routing: { available: boolean; provider?: string | null }; case_escalation: { available: boolean; provider?: string | null }; modules: Record; consequences: Record; }; export type TicketHistoryEntry = { revision: number; event_type: string; occurred_at: string; actor_id?: string | null; reason: string; details: Record; }; export function listTickets( settings: ApiSettings, options: { statuses?: string[]; priorities?: string[]; ticketTypes?: string[]; queueRef?: string; query?: string; limit?: number }, signal?: AbortSignal ): Promise { return apiFetch(settings, apiPath("/api/v1/tickets", { status: options.statuses, priority: options.priorities, ticket_type: options.ticketTypes, queue_ref: options.queueRef, query: options.query, limit: options.limit }), { signal }); } export function getTicketAvailability(settings: ApiSettings, signal?: AbortSignal): Promise { return apiFetch(settings, "/api/v1/tickets/availability", { signal }); } export function getTicket(settings: ApiSettings, ticketId: string, signal?: AbortSignal): Promise { return apiFetch(settings, `/api/v1/tickets/${encodeURIComponent(ticketId)}`, { signal }); } export function listTicketHistory(settings: ApiSettings, ticketId: string, signal?: AbortSignal): Promise<{ history: TicketHistoryEntry[] }> { return apiFetch(settings, `/api/v1/tickets/${encodeURIComponent(ticketId)}/history`, { signal }); } export function createTicket(settings: ApiSettings, record: TicketRecord): Promise { return apiFetch(settings, "/api/v1/tickets", { method: "POST", body: JSON.stringify({ record, idempotency_key: crypto.randomUUID() }) }); } function mutation(record: TicketRecord, changeReason: string) { return { expected_revision: record.revision, recorded_at: new Date().toISOString(), change_reason: changeReason, idempotency_key: crypto.randomUUID() }; } export function triageTicket(settings: ApiSettings, record: TicketRecord, changes: Record, changeReason: string): Promise { return apiFetch(settings, `/api/v1/tickets/${encodeURIComponent(record.ticket_id)}/triage`, { method: "PATCH", body: JSON.stringify({ ...mutation(record, changeReason), changes }) }); } export function assignTicket(settings: ApiSettings, record: TicketRecord, assignee: TicketSubject | null, changeReason: string): Promise { return apiFetch(settings, `/api/v1/tickets/${encodeURIComponent(record.ticket_id)}/assignment`, { method: "POST", body: JSON.stringify({ ...mutation(record, changeReason), assignee }) }); } export function replaceTicketParticipants(settings: ApiSettings, record: TicketRecord, participants: TicketSubject[], changeReason: string): Promise { return apiFetch(settings, `/api/v1/tickets/${encodeURIComponent(record.ticket_id)}/participants`, { method: "PUT", body: JSON.stringify({ ...mutation(record, changeReason), participants }) }); } export function addTicketLink(settings: ApiSettings, record: TicketRecord, link: TicketLink, changeReason: string): Promise { return apiFetch(settings, `/api/v1/tickets/${encodeURIComponent(record.ticket_id)}/links`, { method: "POST", body: JSON.stringify({ ...mutation(record, changeReason), link }) }); } export function removeTicketLink(settings: ApiSettings, record: TicketRecord, linkId: string, changeReason: string): Promise { return apiFetch(settings, `/api/v1/tickets/${encodeURIComponent(record.ticket_id)}/links/${encodeURIComponent(linkId)}`, { method: "DELETE", body: JSON.stringify({ ...mutation(record, changeReason), changes: {} }) }); } export function resolveTicket( settings: ApiSettings, record: TicketRecord, targetStatus: string, resolutionSummary: string | null, changeReason: string ): Promise { return apiFetch(settings, `/api/v1/tickets/${encodeURIComponent(record.ticket_id)}/resolution`, { method: "POST", body: JSON.stringify({ ...mutation(record, changeReason), target_status: targetStatus, resolution_summary: resolutionSummary }) }); } export function addTicketComment(settings: ApiSettings, record: TicketRecord, body: string, visibility: "internal" | "external") { return apiFetch(settings, `/api/v1/tickets/${encodeURIComponent(record.ticket_id)}/comments`, { method: "POST", body: JSON.stringify({ expected_revision: record.revision, comment_id: crypto.randomUUID(), body, visibility, recorded_at: new Date().toISOString(), idempotency_key: crypto.randomUUID() }) }) as Promise<{ ticket: TicketRecord; comment: Record }>; } export function escalateTicket(settings: ApiSettings, record: TicketRecord, caseTypeKey: string, handoffNote: string) { return apiFetch(settings, `/api/v1/tickets/${encodeURIComponent(record.ticket_id)}/case-escalations`, { method: "POST", body: JSON.stringify({ expected_revision: record.revision, case_type_key: caseTypeKey, handoff_note: handoffNote || null, occurred_at: new Date().toISOString(), idempotency_key: crypto.randomUUID() }) }) as Promise<{ ticket: TicketRecord; escalation: Record }>; } export function deleteTicket(settings: ApiSettings, record: TicketRecord, reason: string): Promise { return apiFetch(settings, `/api/v1/tickets/${encodeURIComponent(record.ticket_id)}`, { method: "DELETE", body: JSON.stringify({ expected_revision: record.revision, occurred_at: new Date().toISOString(), reason, idempotency_key: crypto.randomUUID() }) }); }