import { config } from '../../../config';
import { useAuthStore } from '../../../auth/auth-store';

/**
 * Shared fetch helper for admin API endpoints.
 *
 * On a 401 response the helper attempts a single token refresh and retries
 * the original request.  Only if the retry also fails (or there is no refresh
 * token) does it fall through to the normal error path.
 *
 * Previously this function called `logout()` directly on 401/403 which could
 * race with background polling: when an access-token expired while the user
 * was editing a form, the immediate logout cleared `roles`, causing
 * `RequireAdmin` to redirect to `/` -> `/exchanges` and losing unsaved state.
 */
export async function adminFetch<T>(path: string, options?: RequestInit): Promise<T> {
  const res = await _doFetch(path, options);

  // 401 — attempt a token refresh and retry once
  if (res.status === 401) {
    const refreshed = await useAuthStore.getState().refresh();
    if (refreshed) {
      const retry = await _doFetch(path, options);
      return _handleResponse<T>(retry);
    }
    // Refresh failed — throw without calling logout().
    // The central onUnauthorized handler (use-auth.ts) will take care of
    // redirecting to /login if appropriate.
    throw new Error('Unauthorized');
  }

  return _handleResponse<T>(res);
}

async function _doFetch(path: string, options?: RequestInit): Promise<Response> {
  const token = useAuthStore.getState().accessToken;
  return fetch(`${config.apiBaseUrl}/admin${path}`, {
    ...options,
    headers: {
      'Content-Type': 'application/json',
      ...(token ? { Authorization: `Bearer ${token}` } : {}),
      'X-Cameleer-Protocol-Version': '1',
      ...options?.headers,
    },
  });
}

async function _handleResponse<T>(res: Response): Promise<T> {
  if (res.status === 401 || res.status === 403) {
    throw new Error('Unauthorized');
  }
  if (!res.ok) {
    let message = `API error: ${res.status}`;
    try {
      const body = await res.json();
      if (body?.error) message = body.error;
      else if (body?.message) message = body.message;
    } catch {
      // no JSON body — keep generic message
    }
    throw new Error(message);
  }
  if (res.status === 204) return undefined as T;
  const text = await res.text();
  if (!text) return undefined as T;
  return JSON.parse(text);
}
