/**
 * AdiaUI Transport — Self-contained vanilla JS bundle.
 * Fetch wrapper with timeout, retries, error normalization.
 *
 * Zero dependencies. Drop into CodePen, StackBlitz, or any vanilla project.
 */

export async function request(url, options = {}) {
  const { init = {}, timeout = 30_000, retries = 0, retryDelay = 1000, signal } = options;

  for (let attempt = 0; attempt <= retries; attempt++) {
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), timeout);

    if (signal) {
      if (signal.aborted) { clearTimeout(timeoutId); throw new TransportError('Request aborted', { kind: 'abort' }); }
      signal.addEventListener('abort', () => controller.abort(), { once: true });
    }

    try {
      const response = await fetch(url, { ...init, signal: controller.signal });
      clearTimeout(timeoutId);

      if (!response.ok && attempt < retries && response.status >= 500) {
        await sleep(retryDelay * Math.pow(2, attempt));
        continue;
      }

      return response;
    } catch (err) {
      clearTimeout(timeoutId);

      if (err.name === 'AbortError') {
        throw new TransportError(signal?.aborted ? 'Request aborted' : 'Request timed out', {
          kind: signal?.aborted ? 'abort' : 'timeout',
          cause: err,
        });
      }

      if (attempt < retries) {
        await sleep(retryDelay * Math.pow(2, attempt));
        continue;
      }

      throw new TransportError(`Network error: ${err.message}`, {
        kind: 'network',
        cause: err,
      });
    }
  }
}

export async function json(url, options = {}) {
  const response = await request(url, options);
  if (!response.ok) {
    let body;
    try { body = await response.json(); } catch { body = await response.text().catch(() => ''); }
    throw new TransportError(`HTTP ${response.status}: ${response.statusText}`, {
      kind: 'http',
      status: response.status,
      body,
    });
  }
  return response.json();
}

export class TransportError extends Error {
  constructor(message, { kind, status, body, cause } = {}) {
    super(message, { cause });
    this.name = 'TransportError';
    this.kind = kind;
    this.status = status;
    this.body = body;
  }
}

function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
