export function ViewpointApiClient(baseUrl: string, token: string) {
  return async function ViewpointFetch<TResponse>(
    path: string,
    init?: RequestInit,
  ): Promise<TResponse | null> {
    const response = await fetch(`${baseUrl}${path}`, {
      ...init,
      headers: {
        ...(init?.headers ?? {}),
        api_key: token,
        Accept: "application/json",
        "Content-Type": "application/json",
      },
    });
    if (!response.ok) {
      console.log(await response.json());
      console.log(
        `Viewpoint API error: ${response.status} ${response.statusText}`,
      );
      return null;
    }

    const contentType = response.headers.get("content-type");

    if (contentType?.includes("application/json")) {
      return (await response.json()) as TResponse;
    }
    return (await response.text()) as TResponse;
  };
}

/**
 * A client for writes that must not fail quietly.
 *
 * `ViewpointApiClient` logs a failed response and returns `null`, which reads the
 * same as "Viewpoint had nothing for you". That is tolerable for a lookup and wrong
 * for a mutation: a caller that changes an account status needs to know whether the
 * change landed, and a `null` would let it record a success it never got. This one
 * throws instead, carrying the status and the body Viewpoint sent back.
 */
export class ViewpointApiError extends Error {
  constructor(
    readonly status: number,
    readonly body: string,
    message: string,
  ) {
    super(message);
    this.name = "ViewpointApiError";
  }
}

export function ViewpointApiWriteClient(baseUrl: string, token: string) {
  return async function ViewpointWrite<TResponse>(
    path: string,
    init?: RequestInit,
  ): Promise<TResponse> {
    const response = await fetch(`${baseUrl}${path}`, {
      ...init,
      headers: {
        ...(init?.headers ?? {}),
        api_key: token,
        Accept: "application/json",
        "Content-Type": "application/json",
      },
    });

    const raw = await response.text();

    if (!response.ok) {
      throw new ViewpointApiError(
        response.status,
        raw,
        `Viewpoint API error: ${response.status} ${response.statusText}`,
      );
    }

    const contentType = response.headers.get("content-type");
    if (contentType?.includes("application/json")) {
      return JSON.parse(raw) as TResponse;
    }
    return raw as TResponse;
  };
}
