/**
 * Fetch wrapper: on 401 from /api/* response, attempts /api/auth/refresh.
 * Retries the original request once. If refresh also returns 401, surfaces
 * the original 401 to the caller (caller decides whether to redirect to /login).
 *
 * Concurrent 401s share a single refresh promise — no thundering herd.
 */

import { captureCaught } from '@/lib/observability';
let inflightRefresh: Promise<boolean> | null = null;

async function refreshOnce(): Promise<boolean> {
  if (inflightRefresh) return inflightRefresh;
  inflightRefresh = (async () => {
    try {
      const res = await fetch('/api/auth/refresh', {
        method: 'POST',
        credentials: 'same-origin',
        headers: { 'Content-Type': 'application/json' },
        body: '{}',
      });
      return res.ok;
    } catch (err) {
      captureCaught(err, { scope: 'lib.api.refresh-on-401', severity: 'warning' });
      return false;
    } finally {
      // Clear after small delay so simultaneous 401s share this promise
      setTimeout(() => {
        inflightRefresh = null;
      }, 100);
    }
  })();
  return inflightRefresh;
}

export async function fetchWithRefresh(
  input: RequestInfo | URL,
  init?: RequestInit,
): Promise<Response> {
  const res = await fetch(input, init);
  if (res.status !== 401) return res;
  // Only attempt refresh for same-origin /api/* paths
  const url =
    typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url;
  if (!url.startsWith('/api/') && !url.includes('/api/')) return res;
  if (url.includes('/api/auth/refresh')) return res; // don't refresh-loop the refresh endpoint
  const ok = await refreshOnce();
  if (!ok) return res;
  return fetch(input, init);
}
