import { SkimlyHTTPError, SkimlyNetworkError } from './errors.js';
export async function postJSON(path, payload, opts) {
    const { base, key, timeoutMs = 30000, retries = 2 } = opts;
    const maxAttempts = Math.max(1, 1 + retries); // first try + extra retries
    for (let attempt = 1; attempt <= maxAttempts; attempt++) {
        const ac = new AbortController();
        const timer = setTimeout(() => ac.abort(), timeoutMs);
        try {
            const res = await fetch(join(base, path), {
                method: 'POST',
                headers: {
                    'Authorization': `Bearer ${key}`,
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify(payload),
                signal: ac.signal,
            });
            if (!res.ok) {
                const text = await res.text().catch(() => '');
                const err = new SkimlyHTTPError(res.status, res.statusText, text);
                // retry 5xx only
                if (res.status >= 500 && attempt < maxAttempts) {
                    await backoff(attempt);
                    continue;
                }
                throw err;
            }
            // success
            return await res.json();
        }
        catch (e) {
            // Timeout or network error from fetch throws (AbortError/TypeError)
            const isAbort = e?.name === 'AbortError';
            const isTypeErr = e instanceof TypeError; // node-fetch style network error
            const retryable = isAbort || isTypeErr;
            if (retryable && attempt < maxAttempts) {
                await backoff(attempt);
                continue;
            }
            throw new SkimlyNetworkError(e?.message || 'Network/timeout error', e);
        }
        finally {
            clearTimeout(timer);
        }
    }
    // Unreachable, but TS wants a return/throw
    throw new SkimlyNetworkError('Exhausted retries');
}
function join(base, path) {
    return `${base.replace(/\/$/, '')}${path}`;
}
function sleep(ms) {
    return new Promise((r) => setTimeout(r, ms));
}
async function backoff(attempt) {
    // attempt starts at 1 → 200ms, 400ms, 800ms...
    const ms = 200 * Math.pow(2, attempt - 1);
    await sleep(ms);
}
