import { configuredBackendUrl } from "@/lib/backend-url"
import {
  getToken,
  isAuthEnabled,
  redirectToPortalLogin,
  redirectToPortalLoginInteractive,
} from "@/lib/auth"

export class ApiClientError extends Error {
  constructor(
    message: string,
    public readonly status: number,
    public readonly payload?: unknown,
  ) {
    super(message)
    this.name = "ApiClientError"
  }
}

function trimBaseUrl(baseUrl: string): string {
  return baseUrl.replace(/\/$/, "")
}

function resolveRequestUrl(baseUrl: string, path: string): string {
  if (path.startsWith("/") && configuredBackendUrl().kind === "same-origin") {
    return path
  }
  return trimBaseUrl(baseUrl) + path
}

export async function requestJson<T>(
  baseUrl: string,
  path: string,
  init?: RequestInit,
): Promise<T> {
  const hasBody = init?.body != null
  const headers = new Headers(init?.headers)
  if (hasBody && !headers.has("Content-Type")) {
    headers.set("Content-Type", "application/json")
  }
  const token = typeof window !== "undefined" ? getToken() : null
  if (token && !headers.has("Authorization")) {
    headers.set("Authorization", `Bearer ${token}`)
  }

  const res = await fetch(resolveRequestUrl(baseUrl, path), {
    ...init,
    headers,
  })

  if (res.status === 401 && typeof window !== "undefined" && isAuthEnabled()) {
    const ok = redirectToPortalLogin()
    if (!ok) redirectToPortalLoginInteractive()
    throw new ApiClientError("Unauthorized", 401)
  }

  if (res.status === 204) return undefined as T

  const payload = await res.json().catch(() => undefined)
  if (!res.ok) {
    const msg =
      typeof payload === "object" &&
      payload !== null &&
      "error" in payload &&
      typeof (payload as { error?: unknown }).error === "string"
        ? (payload as { error: string }).error
        : res.statusText
    throw new ApiClientError(msg, res.status, payload)
  }

  return payload as T
}
