let serverUrl: string | null = null;
let serviceToken: string | null = null;

export async function initApiConfig() {
  try {
    const res = await fetch('/api/settings');
    const settings = (await res.json()) as { serverURL: string; serviceToken?: string };
    serverUrl = settings.serverURL;
    serviceToken = settings.serviceToken || null;
  } catch (err) {
    console.error('failed to load api config', err);
  }
}

function isUpstreamPath(path: string): boolean {
  return path.startsWith('/my/') || path.startsWith('/admin/') || path.startsWith('/client/');
}

function getBaseUrl(path: string): string {
  if (isUpstreamPath(path)) {
    return serverUrl || 'http://10.0.0.11:3201';
  }
  return typeof window !== 'undefined' && window.location.port === '8765'
    ? `http://${window.location.hostname}:8765`
    : '';
}

export class ApiError extends Error {
  constructor(
    public readonly status: number,
    public readonly path: string,
  ) {
    super(`HTTP ${status} from ${path}`);
    this.name = 'ApiError';
  }
}

export async function apiGet<T>(path: string): Promise<T> {
  try {
    const base = getBaseUrl(path);
    const headers: HeadersInit = {};
    if (serviceToken && isUpstreamPath(path)) {
      headers['Authorization'] = `Bearer ${serviceToken}`;
    }
    const res = await fetch(`${base}${path}`, { credentials: 'include', headers });
    if (!res.ok) throw new ApiError(res.status, path);
    const contentType = res.headers.get('content-type') ?? '';
    if (!contentType.includes('application/json')) {
      throw new ApiError(res.status, `${path} (expected JSON, got ${contentType || 'unknown'})`);
    }
    return res.json() as Promise<T>;
  } catch (err) {
    if (err instanceof ApiError) throw err;
    throw new ApiError(0, path);
  }
}

export async function apiPut<T>(path: string, body: unknown): Promise<T> {
  try {
    const base = getBaseUrl(path);
    const headers: HeadersInit = { 'Content-Type': 'application/json' };
    if (serviceToken && isUpstreamPath(path)) {
      headers['Authorization'] = `Bearer ${serviceToken}`;
    }
    const res = await fetch(`${base}${path}`, {
      method: 'PUT',
      headers,
      body: JSON.stringify(body),
      credentials: 'include',
    });
    if (!res.ok) throw new ApiError(res.status, path);
    return res.json() as Promise<T>;
  } catch (err) {
    if (err instanceof ApiError) throw err;
    throw new ApiError(0, path);
  }
}

export async function apiPost<T>(path: string, body?: unknown): Promise<T> {
  try {
    const base = getBaseUrl(path);
    const headers: HeadersInit = { 'Content-Type': 'application/json' };
    if (serviceToken && isUpstreamPath(path)) {
      headers['Authorization'] = `Bearer ${serviceToken}`;
    }
    const res = await fetch(`${base}${path}`, {
      method: 'POST',
      headers,
      body: body !== undefined ? JSON.stringify(body) : null,
      credentials: 'include',
    });
    if (!res.ok) throw new ApiError(res.status, path);
    return res.json() as Promise<T>;
  } catch (err) {
    if (err instanceof ApiError) throw err;
    throw new ApiError(0, path);
  }
}

export async function apiDelete<T>(path: string): Promise<T> {
  try {
    const base = getBaseUrl(path);
    const headers: HeadersInit = {};
    if (serviceToken && isUpstreamPath(path)) {
      headers['Authorization'] = `Bearer ${serviceToken}`;
    }
    const res = await fetch(`${base}${path}`, {
      method: 'DELETE',
      credentials: 'include',
      headers,
    });
    if (!res.ok) throw new ApiError(res.status, path);
    return res.json() as Promise<T>;
  } catch (err) {
    if (err instanceof ApiError) throw err;
    throw new ApiError(0, path);
  }
}
