/**
 * Client-side fetch wrapper that transparently handles 401 responses by
 * attempting one token refresh, then retrying the original request.
 *
 * Usage: replace `fetch(...)` with `apiFetch(...)` everywhere in client
 * components that call internal Next.js API routes (/api/*).
 *
 * If the refresh also fails the user is redirected to /auth.
 */

let refreshing: Promise<boolean> | null = null;

async function doRefresh(): Promise<boolean> {
  try {
    const res = await fetch("/api/auth/refresh", {
      method: "POST",
      credentials: "same-origin",
    });
    return res.ok;
  } catch {
    return false;
  }
}

/** Deduplicated refresh — at most one in-flight at a time. */
async function refreshOnce(): Promise<boolean> {
  if (!refreshing) {
    refreshing = doRefresh().finally(() => {
      refreshing = null;
    });
  }
  return refreshing;
}

export async function apiFetch(
  input: RequestInfo | URL,
  init?: RequestInit
): Promise<Response> {
  const res = await fetch(input, { credentials: "same-origin", ...init });

  if (res.status !== 401) return res;

  // Try refreshing the token once
  const refreshed = await refreshOnce();
  if (!refreshed) {
    // Session is truly dead — redirect to login
    const next = encodeURIComponent(window.location.pathname + window.location.search);
    window.location.href = `/auth?next=${next}`;
    // Return the original 401 so callers don't hang
    return res;
  }

  // Retry the original request with the new cookie
  return fetch(input, { credentials: "same-origin", ...init });
}
