export class ApiError extends Error {
	constructor(
		message: string,
		public status: number,
	) {
		super(message);
		this.name = "ApiError";
	}
}

async function handleResponse<T>(res: Response): Promise<T> {
	if (!res.ok) {
		let message = `Request failed with status ${res.status}`;
		try {
			const body = await res.json();
			if (body.error) message = body.error;
		} catch {
			// Use default message
		}
		throw new ApiError(message, res.status);
	}
	return res.json() as Promise<T>;
}

export async function apiGet<T>(url: string): Promise<T> {
	const res = await fetch(url);
	return handleResponse<T>(res);
}

export async function apiPost<T>(url: string, body: unknown): Promise<T> {
	const res = await fetch(url, {
		method: "POST",
		headers: { "Content-Type": "application/json" },
		body: JSON.stringify(body),
	});
	return handleResponse<T>(res);
}

export async function apiPut<T>(url: string, body: unknown): Promise<T> {
	const res = await fetch(url, {
		method: "PUT",
		headers: { "Content-Type": "application/json" },
		body: JSON.stringify(body),
	});
	return handleResponse<T>(res);
}

export async function apiPatch<T>(url: string, body: unknown): Promise<T> {
	const res = await fetch(url, {
		method: "PATCH",
		headers: { "Content-Type": "application/json" },
		body: JSON.stringify(body),
	});
	return handleResponse<T>(res);
}

export async function apiDelete<T>(url: string): Promise<T> {
	const res = await fetch(url, { method: "DELETE" });
	return handleResponse<T>(res);
}

export async function apiUpload<T>(url: string, file: File): Promise<T> {
	const formData = new FormData();
	formData.append("image", file);
	const res = await fetch(url, {
		method: "POST",
		body: formData,
	});
	return handleResponse<T>(res);
}
