function normalizeApiBase(value: string): string {
  const base = value.replace(/\/+$/, '')
  return /\/api\/v1$/.test(base) ? base : `${base}/api/v1`
}

function resolveApiBase(): string {
  if (typeof window === 'undefined') {
    return normalizeApiBase(process.env.API_INTERNAL_URL ?? process.env.API_URL ?? 'http://localhost:4000/api/v1')
  }

  // Same-origin is the production default. Direct cross-subdomain API calls are
  // opt-in because host-only cookies otherwise become invisible to sibling apps.
  if (process.env.NEXT_PUBLIC_CARPLACE_DIRECT_API === 'true' && process.env.NEXT_PUBLIC_API_URL) {
    return normalizeApiBase(process.env.NEXT_PUBLIC_API_URL)
  }

  return '/carplace/api/v1'
}

export const API_BASE = resolveApiBase()

export class CarplaceApiError extends Error {
  status: number
  code?: string
  nextAvailableAt?: string | null

  constructor(message: string, status: number, code?: string, nextAvailableAt?: string | null) {
    super(message)
    this.name = 'CarplaceApiError'
    this.status = status
    this.code = code
    this.nextAvailableAt = nextAvailableAt
  }
}

async function parseResponse<T>(res: Response): Promise<T> {
  const json = await res.json().catch(() => null)
  if (!res.ok) throw new CarplaceApiError(json?.message ?? 'Request failed', res.status, json?.error, json?.nextAvailableAt)
  return (json?.data ?? json) as T
}

export async function carplaceFetch<T>(path: string, init?: RequestInit): Promise<T> {
  const res = await fetch(`${API_BASE}${path}`, {
    cache: 'no-store',
    credentials: 'include',
    ...init,
  })
  return parseResponse<T>(res)
}

export async function carplaceFetchOrDefault<T>(path: string, fallback: T): Promise<T> {
  try {
    return await carplaceFetch<T>(path)
  } catch {
    return fallback
  }
}

export async function carplacePost<T>(path: string, body: unknown, init?: Omit<RequestInit, 'method' | 'body'>): Promise<T> {
  const res = await fetch(`${API_BASE}${path}`, {
    ...init,
    method: 'POST',
    credentials: 'include',
    headers: {
      'Content-Type': 'application/json',
      ...(init?.headers ?? {}),
    },
    body: JSON.stringify(body),
  })
  return parseResponse<T>(res)
}
