import type { AttendeeDto, AttendeeList, BulkCreateAttendees, BulkCreateAttendeesResult, ConnectPayment, ConnectPaymentResult, CreateAttendee, CreateAttendeeResult, CreateFirstGroup, CreateFirstGroupResult, CreateGroupResult, CreateGroupWaitlistEntry, GroupDto, GroupInviteInfoDto, GroupList, GroupWaitlistEntryDto, GroupWaitlistList, InviteTokenResult, JoinGroupViaInvite, JoinGroupViaInviteResult, OnboardingStatusDto, ProblemDetails, PromoteGroupWaitlistEntryResult, RemoveAttendeeResult, RemoveGroupWaitlistEntryResult, } from '@gruperly/shared' const API_URL = import.meta.env.VITE_API_URL ?? 'http://localhost:4000' export class ApiError extends Error { constructor( readonly status: number, readonly problem: ProblemDetails | null, ) { super(problem?.detail ?? problem?.title ?? `Error ${status}`) this.name = 'ApiError' } } type JsonBody = Record | unknown[] async function apiFetch(path: string, init?: RequestInit): Promise { const headers = new Headers(init?.headers) headers.set('Content-Type', 'application/json') const res = await fetch(`${API_URL}${path}`, { ...init, headers, credentials: 'include', }) if (!res.ok) { let problem: ProblemDetails | null = null try { const body = (await res.json()) as Partial if (body && typeof body === 'object' && typeof body.title === 'string') { problem = body as ProblemDetails } } catch { // Sin cuerpo JSON: usamos el error genérico. } throw new ApiError(res.status, problem) } return (await res.json()) as T } export const getOnboardingStatus = () => apiFetch('/api/v1/onboarding/status') export const connectPayment = (payload: ConnectPayment) => apiFetch('/api/v1/onboarding/payment-setup', { method: 'POST', body: JSON.stringify(payload), }) export const createFirstGroup = (payload: CreateFirstGroup) => apiFetch('/api/v1/onboarding/first-group', { method: 'POST', body: JSON.stringify(payload), }) export const createGroup = (payload: CreateFirstGroup) => apiFetch('/api/v1/groups', { method: 'POST', body: JSON.stringify(payload), }) export const getGroups = () => apiFetch('/api/v1/groups') export const getGroup = (groupId: string) => apiFetch(`/api/v1/groups/${groupId}`) export const getInviteToken = (groupId: string, regenerate = false) => regenerate ? apiFetch(`/api/v1/groups/${groupId}/invite-token?regenerate=true`, { method: 'POST', }) : apiFetch(`/api/v1/groups/${groupId}/invite-token`) export const getInviteInfo = (token: string) => apiFetch(`/api/v1/invitations/${token}`) export const joinViaInvite = (token: string, payload: JoinGroupViaInvite) => apiFetch(`/api/v1/invitations/${token}/join`, { method: 'POST', body: JSON.stringify(payload), }) export const createAttendee = ( groupId: string, payload: CreateAttendee, options?: { allowOverflow?: boolean }, ) => apiFetch( `/api/v1/groups/${groupId}/attendees${options?.allowOverflow ? '?allowOverflow=true' : ''}`, { method: 'POST', body: JSON.stringify(payload), }, ) export const addToGroupWaitlist = (groupId: string, payload: CreateGroupWaitlistEntry) => apiFetch(`/api/v1/groups/${groupId}/waitlist`, { method: 'POST', body: JSON.stringify(payload), }) export const bulkCreateAttendees = (groupId: string, payload: BulkCreateAttendees) => apiFetch(`/api/v1/groups/${groupId}/attendees/bulk`, { method: 'POST', body: JSON.stringify(payload), }) export const getGroupAttendees = (groupId: string, page = 1, pageSize = 20) => apiFetch(`/api/v1/groups/${groupId}/attendees?page=${page}&pageSize=${pageSize}`) export const getGroupWaitlist = (groupId: string, page = 1, pageSize = 100) => apiFetch(`/api/v1/groups/${groupId}/waitlist?page=${page}&pageSize=${pageSize}`) export const promoteGroupWaitlistEntry = (groupId: string, entryId: string) => apiFetch(`/api/v1/groups/${groupId}/waitlist/${entryId}/promote`, { method: 'POST', }) export const removeGroupWaitlistEntry = (groupId: string, entryId: string) => apiFetch(`/api/v1/groups/${groupId}/waitlist/${entryId}`, { method: 'DELETE', }) export const removeGroupAttendee = ( groupId: string, attendeeId: string, options?: { promoteFromWaitlist?: boolean }, ) => apiFetch( `/api/v1/groups/${groupId}/attendees/${attendeeId}${options?.promoteFromWaitlist ? '?promoteFromWaitlist=true' : ''}`, { method: 'DELETE', }, )