import { getServerIntegration, getUserIntegration, upsertUserIntegration } from 'officerdb';
import { PermanentError } from '../../queue/types';

type TokenRefreshResult = { accessToken: string; expiresAt: number };

export async function refreshGoogleAccessToken(refreshToken: string): Promise<TokenRefreshResult> {
  const serverGoogle = await getServerIntegration('google');
  const serverConfig = serverGoogle?.config as Record<string, unknown> | undefined;
  if (!serverConfig?.clientId || !serverConfig?.clientSecret) {
    throw new PermanentError('Google OAuth not configured on server');
  }

  const response = await fetch('https://oauth2.googleapis.com/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      client_id: serverConfig.clientId as string,
      client_secret: serverConfig.clientSecret as string,
      refresh_token: refreshToken,
      grant_type: 'refresh_token',
    }),
  });

  if (!response.ok) {
    const text = await response.text();
    throw new Error(`Google token refresh failed: ${text}`);
  }

  const data = (await response.json()) as { access_token: string; expires_in: number };
  return {
    accessToken: data.access_token,
    expiresAt: Date.now() + data.expires_in * 1000,
  };
}

// Returns a non-expired Google access token for the user, refreshing and
// persisting a new one when the stored token is within 60s of expiry.
// Returns null if the user has no stored token to work with.
export async function getValidGoogleAccessToken(userId: number): Promise<string | null> {
  const integration = await getUserIntegration(userId, 'google');
  const config = integration?.config as Record<string, unknown> | undefined;
  if (!config) return null;

  const accessToken = config.accessToken as string | undefined;
  const refreshToken = config.refreshToken as string | undefined;
  const expiresAt = config.expiresAt as number | undefined;
  if (!accessToken) return null;

  const expired = !expiresAt || expiresAt < Date.now() + 60_000;
  if (!expired || !refreshToken) return accessToken;

  const refreshed = await refreshGoogleAccessToken(refreshToken);
  const serverGoogle = await getServerIntegration('google');
  await upsertUserIntegration({
    userId,
    provider: 'google',
    serverIntegrationId: serverGoogle?.id,
    config: { ...config, accessToken: refreshed.accessToken, expiresAt: refreshed.expiresAt },
  });
  return refreshed.accessToken;
}
