// #486: Shared apiJson + ApiError so the upcoming-meeting-alert
// PostponeDialog and the new schedule row quick-actions popover both
// inspect the same structured 409 stale_meeting payload (used by the
// postpone-minutes and swap-times endpoints) without duplicating the
// fetch wrapper.

export class ApiError extends Error {
  status: number;
  code: string | undefined;
  body: Record<string, unknown>;
  constructor(message: string, status: number, body: Record<string, unknown>) {
    super(message);
    this.name = "ApiError";
    this.status = status;
    this.body = body;
    const code = (body as { code?: unknown }).code;
    this.code = typeof code === "string" ? code : undefined;
  }
}

export async function apiJson<T>(
  input: string,
  init?: RequestInit,
): Promise<T> {
  const res = await fetch(input, {
    credentials: "include",
    headers: { "Content-Type": "application/json", ...(init?.headers ?? {}) },
    ...init,
  });
  if (res.status === 204) return undefined as T;
  const text = await res.text();
  const data = text ? (JSON.parse(text) as unknown) : ({} as unknown);
  if (!res.ok) {
    const body = (data ?? {}) as Record<string, unknown>;
    const message =
      (body.error as string | undefined) || `HTTP ${res.status}`;
    throw new ApiError(message, res.status, body);
  }
  return data as T;
}
