import 'dotenv/config';

declare const fetch: typeof globalThis.fetch;

export type GraphUserToken = {
  accessToken: string;
  // Optional unix ms epoch indicating when token expires
  expiresAt?: number;
};

// Lightweight in-memory cache (persists while process runs)
let cached: GraphUserToken | null = null;

export function setDelegatedToken(token: string, expiresAt?: number) {
  cached = { accessToken: token, expiresAt };
}

export function getDelegatedToken(): GraphUserToken | null {
  return cached;
}

async function acquireAppOnlyToken(): Promise<GraphUserToken> {
  const clientId = process.env.CLIENT_ID;
  const clientSecret = process.env.CLIENT_SECRET;
  const tenantId = process.env.TENANT_ID;

  if (!clientId || !clientSecret || !tenantId) {
    throw new Error('App-only auth requires CLIENT_ID, CLIENT_SECRET, and TENANT_ID');
  }

  const tokenUrl = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
  const params = new URLSearchParams({
    client_id: clientId,
    client_secret: clientSecret,
    scope: 'https://graph.microsoft.com/.default',
    grant_type: 'client_credentials',
  });

  const resp = await fetch(tokenUrl, {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: params.toString(),
  });

  if (!(resp as any).ok) {
    const text = await (resp as any).text();
    throw new Error(`App-only token acquisition failed: ${(resp as any).status} ${text}`);
  }

  const data = await (resp as any).json();
  const expiresAt = data.expires_in ? Date.now() + data.expires_in * 1000 : undefined;
  return { accessToken: data.access_token, expiresAt };
}

export async function acquireGraphUserToken(): Promise<GraphUserToken> {
  // Return cached token if still valid
  if (cached && (!cached.expiresAt || cached.expiresAt > Date.now())) {
    return cached;
  }

  // Always use app-only authentication (fully automated, no user interaction)
  const appToken = await acquireAppOnlyToken();
  cached = appToken;
  return appToken;
}
