// OIDC Client Wrapper using openid-client

import { Issuer, generators } from 'openid-client';
import { authConfig } from '../config/auth.js';

let oidcClient = null;
let issuer = null;

/**
 * Initialize the OIDC client by discovering the issuer
 */
export async function initializeOIDC() {
  if (!authConfig.app.authEnabled) {
    console.log('[OIDC] Authentication disabled, skipping initialization');
    return null;
  }

  try {
    console.log(`[OIDC] Discovering issuer: ${authConfig.oidc.issuer}`);
    issuer = await Issuer.discover(authConfig.oidc.issuer);
    console.log(`[OIDC] Discovered issuer: ${issuer.issuer}`);

    oidcClient = new issuer.Client({
      client_id: authConfig.oidc.clientId,
      client_secret: authConfig.oidc.clientSecret,
      redirect_uris: [authConfig.oidc.redirectUri],
      response_types: ['code'],
    });

    console.log('[OIDC] Client initialized successfully');
    return oidcClient;
  } catch (error) {
    console.error('[OIDC] Failed to initialize client:', error.message);
    throw error;
  }
}

/**
 * Get the initialized OIDC client
 */
export function getClient() {
  if (!oidcClient) {
    throw new Error('OIDC client not initialized. Call initializeOIDC() first.');
  }
  return oidcClient;
}

/**
 * Generate authorization URL for login
 */
export function getAuthorizationUrl(state, nonce, codeVerifier) {
  const client = getClient();
  const codeChallenge = generators.codeChallenge(codeVerifier);

  return client.authorizationUrl({
    scope: authConfig.oidc.scopes.join(' '),
    state,
    nonce,
    code_challenge: codeChallenge,
    code_challenge_method: 'S256',
  });
}

/**
 * Exchange authorization code for tokens
 */
export async function exchangeCode(code, codeVerifier, nonce) {
  const client = getClient();

  const tokenSet = await client.callback(
    authConfig.oidc.redirectUri,
    { code },
    { code_verifier: codeVerifier, nonce }
  );

  return tokenSet;
}

/**
 * Validate and decode ID token claims
 */
export function getIdTokenClaims(tokenSet) {
  return tokenSet.claims();
}

/**
 * Get user info from the userinfo endpoint
 */
export async function getUserInfo(accessToken) {
  const client = getClient();
  return await client.userinfo(accessToken);
}

/**
 * Refresh access token using refresh token
 */
export async function refreshTokens(refreshToken) {
  const client = getClient();
  return await client.refresh(refreshToken);
}

/**
 * Get end session URL for logout
 */
export function getEndSessionUrl(idTokenHint, postLogoutRedirectUri) {
  const client = getClient();
  return client.endSessionUrl({
    id_token_hint: idTokenHint,
    post_logout_redirect_uri: postLogoutRedirectUri,
  });
}

/**
 * Generate random state for CSRF protection
 */
export function generateState() {
  return generators.state();
}

/**
 * Generate random nonce for ID token validation
 */
export function generateNonce() {
  return generators.nonce();
}

/**
 * Generate code verifier for PKCE
 */
export function generateCodeVerifier() {
  return generators.codeVerifier();
}

export default {
  initializeOIDC,
  getClient,
  getAuthorizationUrl,
  exchangeCode,
  getIdTokenClaims,
  getUserInfo,
  refreshTokens,
  getEndSessionUrl,
  generateState,
  generateNonce,
  generateCodeVerifier,
};
