import type { JWK } from 'jose';
import { exportJWK } from 'jose';
import { createPublicKey } from 'node:crypto';
import type { JwksConfig } from '../config/check-jwks-config';

/**
 * Resolved BFF signing identity — the parsed private key, the
 * derived public JWK (ready to ship in `/.well-known/jwks.json`),
 * the `kid`, and the JOSE algorithm. Computed once at boot from
 * `assertJwksConfig()` so neither the strategy nor the JWKS
 * controller has to re-derive on the hot path.
 *
 * The DI token {@link BFF_SIGNING_KEY} wires this into Nest's
 * provider graph. Both the `SignedAssertionStrategy` (signing) and
 * the JWKS controller (publishing) read from this same instance —
 * one source of truth for the BFF's signing material.
 */
export interface BffSigningKey {
  readonly config: JwksConfig;
  /** Public JWK shape, derived from the private key. Includes `kid`, `alg`, `use=sig`. */
  readonly publicJwk: JWK;
}

export const BFF_SIGNING_KEY = 'BFF_SIGNING_KEY';

/**
 * Builds the {@link BffSigningKey} from the validated env config.
 * Async because `jose.exportJWK` is async on Node — it operates on
 * Web Crypto's KeyObject under the hood.
 */
export async function buildBffSigningKey(config: JwksConfig): Promise<BffSigningKey> {
  // `exportJWK` accepts either a public KeyObject or a CryptoKey.
  // We have the private one — derive the public first so the
  // exported JWK has no private material.
  const publicKey = createPublicKey(config.privateKey);
  const baseJwk = await exportJWK(publicKey);
  const publicJwk: JWK = {
    ...baseJwk,
    kid: config.kid,
    alg: config.alg,
    use: 'sig',
  };
  return { config, publicJwk };
}
