import { SetMetadata, UseGuards, applyDecorators } from '@nestjs/common';
import { REQUIRE_MFA_METADATA, RequireMfaGuard } from './require-mfa.guard';

export interface RequireMfaOptions {
  /**
   * Override of `MFA_FRESHNESS_SECONDS` for this specific route.
   * Useful for surfaces that demand a tighter window than the
   * global default (e.g. admin entry uses 10 min explicitly per
   * ADR-0020). When omitted, the guard reads the env value at
   * resolution time.
   */
  freshness?: number;
}

/**
 * `@RequireMfa()` — gates a route on a recent MFA assertion per
 * [ADR-0011](../../../../docs/decisions/0011-mfa-enforcement-entra-conditional-access.md).
 *
 * Behaviour at the guard:
 *
 *   1. No session → 401 `unauthenticated`.
 *   2. `session.user.amr` carries no MFA-class value → 401
 *      `mfa_required` (SPA interceptor triggers re-auth).
 *   3. `session.mfaVerifiedAt` missing or older than the freshness
 *      window → 401 `mfa_required` (step-up).
 *   4. Otherwise → pass through.
 *
 * Composable with `@RequireAdmin()`: when both are applied (admin
 * entry route per ADR-0020), Nest runs them in registration order.
 * Always put `@RequireMfa()` *outside* `@RequireAdmin()` so the
 * freshness check fires only after the user is established as an
 * admin — keeping the audit log noise-free.
 *
 * Per-route override:
 *
 * ```ts
 * @RequireMfa({ freshness: 600 })  // 10 min, admin entry
 * @Get('me')
 * me() { … }
 * ```
 */
export function RequireMfa(options?: RequireMfaOptions): ClassDecorator & MethodDecorator {
  return applyDecorators(
    SetMetadata(REQUIRE_MFA_METADATA, options ?? {}),
    UseGuards(RequireMfaGuard),
  );
}
