import { authorizedFetch } from './auth/tokens'; type JsonValue = Record; export type TenantEvent = { id: number; name: string | Record; slug: string; event_date: string | null; status: 'draft' | 'published' | 'archived'; is_active?: boolean; description?: string | null; photo_count?: number; like_count?: number; }; export type TenantPhoto = { id: number; filename: string; original_name: string | null; mime_type: string | null; size: number; url: string; thumbnail_url: string; status: string; is_featured: boolean; likes_count: number; uploaded_at: string; uploader_name: string | null; }; export type EventStats = { total: number; featured: number; likes: number; recent_uploads: number; status: string; is_active: boolean; }; type EventListResponse = { data?: TenantEvent[] }; type EventResponse = { data: TenantEvent }; type CreatedEventResponse = { message: string; data: TenantEvent; balance: number }; type PhotoResponse = { message: string; data: TenantPhoto }; type EventSavePayload = { name: string; slug: string; date?: string; status?: 'draft' | 'published' | 'archived'; is_active?: boolean; }; async function jsonOrThrow(response: Response, message: string): Promise { if (!response.ok) { const body = await safeJson(response); console.error('[API]', message, response.status, body); throw new Error(message); } return (await response.json()) as T; } async function safeJson(response: Response): Promise { try { return (await response.clone().json()) as JsonValue; } catch { return null; } } function normalizeEvent(event: TenantEvent): TenantEvent { return { ...event, is_active: typeof event.is_active === 'boolean' ? event.is_active : undefined, }; } function normalizePhoto(photo: TenantPhoto): TenantPhoto { return { id: photo.id, filename: photo.filename, original_name: photo.original_name ?? null, mime_type: photo.mime_type ?? null, size: Number(photo.size ?? 0), url: photo.url, thumbnail_url: photo.thumbnail_url ?? photo.url, status: photo.status ?? 'approved', is_featured: Boolean(photo.is_featured), likes_count: Number(photo.likes_count ?? 0), uploaded_at: photo.uploaded_at, uploader_name: photo.uploader_name ?? null, }; } function eventEndpoint(slug: string): string { return `/api/v1/tenant/events/${encodeURIComponent(slug)}`; } export async function getEvents(): Promise { const response = await authorizedFetch('/api/v1/tenant/events'); const data = await jsonOrThrow(response, 'Failed to load events'); return (data.data ?? []).map(normalizeEvent); } export async function createEvent(payload: EventSavePayload): Promise<{ event: TenantEvent; balance: number }> { const response = await authorizedFetch('/api/v1/tenant/events', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const data = await jsonOrThrow(response, 'Failed to create event'); return { event: normalizeEvent(data.data), balance: data.balance }; } export async function updateEvent(slug: string, payload: Partial): Promise { const response = await authorizedFetch(eventEndpoint(slug), { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const data = await jsonOrThrow(response, 'Failed to update event'); return normalizeEvent(data.data); } export async function getEvent(slug: string): Promise { const response = await authorizedFetch(eventEndpoint(slug)); const data = await jsonOrThrow(response, 'Failed to load event'); return normalizeEvent(data.data); } export async function getEventPhotos(slug: string): Promise { const response = await authorizedFetch(`${eventEndpoint(slug)}/photos`); const data = await jsonOrThrow<{ data?: TenantPhoto[] }>(response, 'Failed to load photos'); return (data.data ?? []).map(normalizePhoto); } export async function featurePhoto(slug: string, id: number): Promise { const response = await authorizedFetch(`${eventEndpoint(slug)}/photos/${id}/feature`, { method: 'POST' }); const data = await jsonOrThrow(response, 'Failed to feature photo'); return normalizePhoto(data.data); } export async function unfeaturePhoto(slug: string, id: number): Promise { const response = await authorizedFetch(`${eventEndpoint(slug)}/photos/${id}/unfeature`, { method: 'POST' }); const data = await jsonOrThrow(response, 'Failed to unfeature photo'); return normalizePhoto(data.data); } export async function deletePhoto(slug: string, id: number): Promise { const response = await authorizedFetch(`${eventEndpoint(slug)}/photos/${id}`, { method: 'DELETE' }); if (!response.ok) { await safeJson(response); throw new Error('Failed to delete photo'); } } export async function toggleEvent(slug: string): Promise { const response = await authorizedFetch(`${eventEndpoint(slug)}/toggle`, { method: 'POST' }); const data = await jsonOrThrow<{ message: string; data: TenantEvent }>(response, 'Failed to toggle event'); return normalizeEvent(data.data); } export async function getEventStats(slug: string): Promise { const response = await authorizedFetch(`${eventEndpoint(slug)}/stats`); const data = await jsonOrThrow(response, 'Failed to load stats'); return { total: Number(data.total ?? 0), featured: Number(data.featured ?? 0), likes: Number(data.likes ?? 0), recent_uploads: Number(data.recent_uploads ?? 0), status: data.status ?? 'draft', is_active: Boolean(data.is_active), }; } export async function createInviteLink(slug: string): Promise<{ link: string; token: string }> { const response = await authorizedFetch(`${eventEndpoint(slug)}/invites`, { method: 'POST' }); return jsonOrThrow<{ link: string; token: string }>(response, 'Failed to create invite'); } export type Package = { id: number; name: string; price: number; max_photos: number | null; max_guests: number | null; gallery_days: number | null; features: Record; }; export async function getPackages(type: 'endcustomer' | 'reseller' = 'endcustomer'): Promise { const response = await authorizedFetch(`/api/v1/packages?type=${type}`); const data = await jsonOrThrow<{ data: Package[] }>(response, 'Failed to load packages'); return data.data ?? []; }