export class ApiError extends Error {
  status: number;

  constructor(status: number, message: string) {
    super(message);
    this.status = status;
  }
}

async function readErrorMessage(res: Response): Promise<string> {
  const contentType = res.headers.get("content-type") || "";
  if (contentType.includes("application/json")) {
    try {
      const data = await res.json();
      if (typeof data?.message === "string") return data.message;
      return JSON.stringify(data);
    } catch {
      return "Request failed";
    }
  }
  try {
    return await res.text();
  } catch {
    return "Request failed";
  }
}

export async function apiPost<TResponse, TBody>(
  path: string,
  body: TBody,
  token?: string
): Promise<TResponse> {
  const res = await fetch(path, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      ...(token ? { Authorization: `Bearer ${token}` } : {}),
    },
    body: JSON.stringify(body),
  });

  if (!res.ok) {
    const msg = await readErrorMessage(res);
    throw new ApiError(res.status, msg || `HTTP ${res.status}`);
  }

  if (res.status === 204) {
    return undefined as TResponse;
  }

  const contentLength = res.headers.get("content-length");
  if (contentLength === "0") {
    return undefined as TResponse;
  }

  const text = await res.text();
  if (!text.trim()) {
    return undefined as TResponse;
  }

  return JSON.parse(text) as TResponse;
}
