/**
 * Shared, auth-attaching API helpers for the FastAPI backend.
 *
 * Every backend request must go through these helpers so the OIDC access token
 * (when auth is enabled) is attached consistently. Rolling a raw `fetch` without
 * these will 401 under `AUTH_ENABLED=true`.
 */

import { getAccessToken } from "../auth";

export const API_BASE = import.meta.env.VITE_API_URL || "/api";

function isAbsoluteUrl(value: string): boolean {
	return /^https?:\/\//i.test(value) || value.startsWith("//");
}

export function buildUrl(
	path: string,
	params?: Record<string, string>,
): string {
	const base = isAbsoluteUrl(API_BASE) ? API_BASE : window.location.origin;
	const url = new URL(path, base);
	if (params) {
		for (const [key, value] of Object.entries(params)) {
			if (value !== undefined && value !== "") {
				url.searchParams.set(key, value);
			}
		}
	}
	return url.toString();
}

export async function readErrorDetail(response: Response): Promise<string> {
	const text = await response.text();
	try {
		const parsed = JSON.parse(text) as { detail?: unknown; message?: unknown };
		const detail = parsed.detail ?? parsed.message;
		if (typeof detail === "string" && detail.trim()) {
			return detail;
		}
	} catch {
		// Fall back to the raw response body below.
	}
	return text;
}

export function buildHeaders(isJsonBody: boolean): Headers {
	const headers = new Headers();
	const token = getAccessToken();
	if (token) headers.set("Authorization", `Bearer ${token}`);
	if (isJsonBody) headers.set("Content-Type", "application/json");
	return headers;
}

export async function get<T>(
	path: string,
	params?: Record<string, string>,
): Promise<T> {
	const response = await fetch(buildUrl(path, params), {
		headers: buildHeaders(false),
	});
	if (!response.ok) {
		throw new Error(`${response.status}: ${await readErrorDetail(response)}`);
	}
	return response.json();
}

export async function post<T>(path: string, body?: unknown): Promise<T> {
	const response = await fetch(buildUrl(path), {
		method: "POST",
		headers: buildHeaders(true),
		body: body ? JSON.stringify(body) : undefined,
	});
	if (!response.ok) {
		throw new Error(`${response.status}: ${await readErrorDetail(response)}`);
	}
	return response.json();
}

export async function postForm<T>(path: string, body: FormData): Promise<T> {
	const response = await fetch(buildUrl(path), {
		method: "POST",
		headers: buildHeaders(false),
		body,
	});
	if (!response.ok) {
		throw new Error(`${response.status}: ${await readErrorDetail(response)}`);
	}
	return response.json();
}

export async function put<T>(path: string, body?: unknown): Promise<T> {
	const response = await fetch(buildUrl(path), {
		method: "PUT",
		headers: buildHeaders(true),
		body: body ? JSON.stringify(body) : undefined,
	});
	if (!response.ok) {
		throw new Error(`${response.status}: ${await readErrorDetail(response)}`);
	}
	return response.json();
}

export async function del<T>(path: string): Promise<T> {
	const response = await fetch(buildUrl(path), {
		method: "DELETE",
		headers: buildHeaders(false),
	});
	if (!response.ok) {
		throw new Error(`${response.status}: ${await readErrorDetail(response)}`);
	}
	return response.json();
}
