import { $API } from '@axium/core/api';
import { errorText } from 'ioium';
import { prettifyError } from 'zod';
// @ts-expect-error 2339
BigInt.prototype.toJSON = function () {
    return Number(this);
};
export let token = null;
export function setToken(value) {
    token = value;
}
export let prefix = '/api/', origin = globalThis.location?.origin || 'https://localhost/';
export function setPrefix(value) {
    prefix = value;
    origin = new URL(prefix, origin).origin;
}
let userAgent = null;
/**
 * Only for use on non-browser clients, e.g. Node.js
 */
export function useUserAgent(ua) {
    userAgent = ua;
}
export async function fetchAPI(method, endpoint, data, ...params) {
    const options = {
        method,
        headers: {
            'Content-Type': 'application/json',
            Accept: 'application/json',
        },
    };
    const schema = $API[endpoint]?.[method];
    if (schema && Array.isArray(schema))
        try {
            data = schema[0].parse(data);
        }
        catch (e) {
            throw prettifyError(e);
        }
    if (token)
        options.headers.Authorization = 'Bearer ' + token;
    if (userAgent)
        options.headers['User-Agent'] = userAgent;
    const parts = [];
    for (const part of endpoint.split('/')) {
        if (!part.startsWith(':')) {
            parts.push(part);
            continue;
        }
        const value = params.shift();
        if (!value)
            throw new Error(`Missing parameter "${part.slice(1)}"`);
        parts.push(value);
    }
    let url = prefix + parts.join('/');
    if (method !== 'GET' && method !== 'HEAD')
        options.body = JSON.stringify(data);
    if (method == 'GET' && typeof data == 'object' && data != null && Object.keys(data).length) {
        const search = new URLSearchParams();
        for (const [key, value] of Object.entries(data)) {
            search.set(key, JSON.stringify(value));
        }
        url += '?' + search.toString();
    }
    const response = await fetch(url, options);
    if (!response.headers.get('Content-Type')?.includes('application/json')) {
        throw new Error(`Unexpected response type: ${response.headers.get('Content-Type')}`);
    }
    const json = await response.json().catch(() => ({ message: 'Unknown server error (invalid JSON response)' }));
    if (!response.ok)
        throw Object.assign(new Error(json.message), { status: response.status });
    if (typeof json == 'object' && json != null && '_warnings' in json) {
        for (const warning of json._warnings)
            console.warn('[API]', warning);
        delete json._warnings;
    }
    if (!schema)
        return json;
    const Output = Array.isArray(schema) ? schema[1] : schema;
    try {
        return Output.parse(json);
    }
    catch (e) {
        throw `${method} ${endpoint}:\n${errorText(e)}`;
    }
}
