import { registerAs } from '@nestjs/config';

export interface FaydaJwk {
  kty: 'RSA';
  use?: string;
  kid?: string;
  alg?: string;
  n: string;
  e: string;
  d: string;
  p?: string;
  q?: string;
  dp?: string;
  dq?: string;
  qi?: string;
}

export type FaydaPlatform = 'WEB' | 'MOBILE';

export interface FaydaConfig {
  enabled: boolean;
  clientId: string;
  authorizationEndpoint: string;
  tokenEndpoint: string;
  userInfoEndpoint: string;
  redirectUri: string;
  privateJwk: FaydaJwk;
  scope: string;
  acrValues: string;
  claimsLocales: string;
  sessionTtlMinutes: number;
}

const REQUIRED_VARS = [
  'FAYDA_CLIENT_ID',
  'FAYDA_AUTHORIZATION_ENDPOINT',
  'FAYDA_TOKEN_ENDPOINT',
  'FAYDA_USERINFO_ENDPOINT',
  'FAYDA_PRIVATE_KEY_BASE64',
] as const;

function decodePrivateJwk(base64: string): FaydaJwk {
  let jwk: unknown;
  try {
    const json = Buffer.from(base64, 'base64').toString('utf8');
    jwk = JSON.parse(json);
  } catch (err) {
    throw new Error(
      `FAYDA_PRIVATE_KEY_BASE64 is not valid Base64-encoded JSON: ${(err as Error).message}`,
    );
  }
  if (!jwk || typeof jwk !== 'object') {
    throw new Error('FAYDA_PRIVATE_KEY_BASE64 must decode to a JSON object');
  }
  const candidate = jwk as Partial<FaydaJwk>;
  if (candidate.kty !== 'RSA') {
    throw new Error('FAYDA_PRIVATE_KEY_BASE64 JWK must have kty="RSA"');
  }
  if (!candidate.n || !candidate.e || !candidate.d) {
    throw new Error(
      'FAYDA_PRIVATE_KEY_BASE64 JWK is missing required RSA private-key fields (n, e, d)',
    );
  }
  return candidate as FaydaJwk;
}

export default registerAs('fayda', (): FaydaConfig => {
  const enabled = (process.env.FAYDA_ENABLED ?? 'false').toLowerCase() === 'true';
  const scope = process.env.FAYDA_SCOPE ?? 'openid profile email';
  const acrValues = process.env.FAYDA_ACR_VALUES ?? 'mosip:idp:acr:generated-code';
  const claimsLocales = process.env.FAYDA_CLAIMS_LOCALES ?? 'en am';
  const sessionTtl = Number.parseInt(process.env.FAYDA_SESSION_TTL_MINUTES ?? '10', 10);
  const redirectUri = process.env.FAYDA_REDIRECT_URI ?? '';
  if (!enabled) {
    return {
      enabled: false,
      clientId: process.env.FAYDA_CLIENT_ID ?? '',
      authorizationEndpoint: process.env.FAYDA_AUTHORIZATION_ENDPOINT ?? '',
      tokenEndpoint: process.env.FAYDA_TOKEN_ENDPOINT ?? '',
      userInfoEndpoint: process.env.FAYDA_USERINFO_ENDPOINT ?? '',
      redirectUri,
      privateJwk: { kty: 'RSA', n: '', e: '', d: '' },
      scope,
      acrValues,
      claimsLocales,
      sessionTtlMinutes: Number.isNaN(sessionTtl) || sessionTtl <= 0 ? 10 : sessionTtl,
    };
  }

  const missing = REQUIRED_VARS.filter((name) => !process.env[name]);
  if (missing.length > 0) {
    throw new Error(
      `Fayda integration is enabled (FAYDA_ENABLED=true) but the following env vars are missing: ${missing.join(', ')}`,
    );
  }
  if (!redirectUri) {
    throw new Error(
      'Fayda integration is enabled but the redirect URI is missing: set FAYDA_REDIRECT_URI',
    );
  }
  if (Number.isNaN(sessionTtl) || sessionTtl <= 0) {
    throw new Error('FAYDA_SESSION_TTL_MINUTES must be a positive integer');
  }

  return {
    enabled: true,
    clientId: process.env.FAYDA_CLIENT_ID!,
    authorizationEndpoint: process.env.FAYDA_AUTHORIZATION_ENDPOINT!,
    tokenEndpoint: process.env.FAYDA_TOKEN_ENDPOINT!,
    userInfoEndpoint: process.env.FAYDA_USERINFO_ENDPOINT!,
    redirectUri,
    privateJwk: decodePrivateJwk(process.env.FAYDA_PRIVATE_KEY_BASE64!),
    scope,
    acrValues,
    claimsLocales,
    sessionTtlMinutes: sessionTtl,
  };
});
