/**
 * Authentik OAuth client for service account authentication.
 * Uses client_credentials grant with token caching.
 */

interface TokenResponse {
  access_token: string
  token_type: string
  expires_in: number
}

interface CachedToken {
  token: string
  expiresAt: number
}

let cachedToken: CachedToken | null = null

/**
 * Get a valid access token, fetching a new one if expired.
 * Tokens are cached with 60s buffer before expiry.
 * 
 * For local dev: set LLM_API_TOKEN env var to skip OAuth.
 */
export async function getAccessToken(): Promise<string> {
  // Local dev fallback - use static token if set
  const staticToken = process.env.LLM_API_TOKEN
  if (staticToken) {
    return staticToken
  }

  const now = Date.now()
  
  // Return cached token if still valid (with 60s buffer)
  if (cachedToken && cachedToken.expiresAt > now + 60000) {
    return cachedToken.token
  }

  const clientId = process.env.AUTHENTIK_CLIENT_ID
  const clientSecret = process.env.AUTHENTIK_CLIENT_SECRET
  const tokenUrl = process.env.AUTHENTIK_TOKEN_URL || 'https://authentik.riotpiao.com/application/o/token/'

  if (!clientId || !clientSecret) {
    throw new Error(
      'Missing OAuth credentials. Set AUTHENTIK_CLIENT_ID + AUTHENTIK_CLIENT_SECRET, ' +
      'or LLM_API_TOKEN for local dev.'
    )
  }

  const response = await fetch(tokenUrl, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    body: new URLSearchParams({
      grant_type: 'client_credentials',
      client_id: clientId,
      client_secret: clientSecret,
      scope: 'openid roles',
    }),
  })

  if (!response.ok) {
    const error = await response.text()
    throw new Error(`Failed to get access token: ${response.status} - ${error}`)
  }

  const data: TokenResponse = await response.json()
  
  cachedToken = {
    token: data.access_token,
    expiresAt: now + (data.expires_in * 1000),
  }

  return cachedToken.token
}
