import React, { type PropsWithChildren } from 'react';

import { initApiClient } from '@/core/api/client';
import { AppSettingsProvider } from '@/core/app-settings-context';
import { NetworkError } from '@/core/api/types';
import { tokenManager } from '@/core/auth/token-manager';
import { config } from '@/core/config';
import { AppQueryProvider, queryClient } from '@/core/query';

/**
 * Returns false only when the refresh token is genuinely rejected
 * (no token stored, or server returned non-2xx).
 * Throws NetworkError on transport-level failures so the caller
 * can distinguish "session dead" from "network down".
 */
async function refreshTokens(): Promise<boolean> {
  const refreshToken = await tokenManager.getRefreshToken();
  if (!refreshToken) return false;

  let res: Response;
  try {
    res = await fetch(`${config.apiBaseUrl}${config.api.refreshPath}`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ refresh_token: refreshToken }),
    });
  } catch (err) {
    throw new NetworkError(
      err instanceof Error ? err.message : 'Token refresh network failure',
      err,
    );
  }

  if (!res.ok) return false;

  const data = (await res.json()) as {
    access_token: string;
    refresh_token: string;
  };
  await tokenManager.setTokens(data.access_token, data.refresh_token);
  return true;
}

/**
 * Called by the API client when token refresh is explicitly rejected.
 * Must synchronously flip query caches so useSession() immediately
 * sees unauthenticated — tokenManager.clearTokens() is fire-and-forget
 * since the cache flip is the authoritative signal.
 */
function onAuthFailure() {
  queryClient.setQueryData(['auth', 'token-check'], false);
  queryClient.setQueryData(['session'], null);
  tokenManager.clearTokens();
}

initApiClient({
  getAccessToken: tokenManager.getAccessToken,
  refreshTokens,
  onAuthFailure,
});

export function AppProviders({ children }: PropsWithChildren) {
  return (
    <AppQueryProvider>
      <AppSettingsProvider>{children}</AppSettingsProvider>
    </AppQueryProvider>
  );
}
