import {
  completeAuthorizationCodeGrant,
  discoverAndValidateOIDCIssuerWellKnown,
  generateOidcAuthorizationUrl,
  OidcClientConfig,
  registerOidcClient,
} from 'matrix-js-sdk';
import { getOidcCallbackUrl, getOidcClientMetadata } from './oidcConfig';
import { cacheClientId, getCachedClientId, invalidateCachedClient } from './oidcState';

export { completeAuthorizationCodeGrant };

export const getOrRegisterClientId = async (
  config: OidcClientConfig,
  issuer: string,
  redirectUri: string,
): Promise<string> => {
  const cached = getCachedClientId(issuer, redirectUri);
  if (cached) return cached;
  const clientId = await registerOidcClient(config, getOidcClientMetadata());
  cacheClientId(issuer, clientId, redirectUri);
  return clientId;
};

/**
 * Begin the OIDC authorization-code flow: discover + validate the issuer,
 * (re)register a client, build the PKCE authorization URL (oidc-client-ts
 * persists the transient code_verifier/state/nonce/homeserverUrl into
 * sessionStorage for the callback), then redirect.
 */
export const startOidcLogin = async (issuer: string, homeserverBaseUrl: string): Promise<void> => {
  const redirectUri = getOidcCallbackUrl();
  try {
    const config = await discoverAndValidateOIDCIssuerWellKnown(issuer);
    const clientId = await getOrRegisterClientId(config, issuer, redirectUri);
    const url = await generateOidcAuthorizationUrl({
      metadata: config,
      redirectUri,
      clientId,
      homeserverUrl: homeserverBaseUrl,
      nonce: crypto.randomUUID(),
    });
    window.location.assign(url);
  } catch (e) {
    // Drop a possibly-stale cached client so the next attempt re-registers.
    invalidateCachedClient(issuer);
    throw e;
  }
};
