<?php

namespace Drupal\miniorange_webauthn\MoService;

use InvalidArgumentException;
use ParagonIE\ConstantTime\Base64UrlSafe;
use Webauthn\AuthenticationExtensions\AuthenticationExtension;
use Webauthn\AuthenticationExtensions\AuthenticationExtensions;
use Webauthn\PublicKeyCredentialRequestOptions;

class MoPubKeyCredReqOptFactory
{
  public function __construct(
    private readonly MoPubKeyReqProfileGenFactory $moPubKeyReqProfileGenFactory
  )
  {
  }
  public function create(
    array $allowCredentials,
    null|string $userVerification = null,
    null|AuthenticationExtensions $AuthenticationExtensions = null
  ): PublicKeyCredentialRequestOptions {
    // todo this process can be made as configurable from admin dynamically and also from req params
    $profile = $this->moPubKeyReqProfileGenFactory->generateRuntimeProfile();

    $rpId = $profile['rp_id'] ?? null;
    $rpId === null || is_string($rpId) || throw new InvalidArgumentException(sprintf(
      'The profile has an invalid rp_id value. Expected a string or null, got "%s".',
      gettype($rpId)
    ));
    $timeout = $profile['timeout'] ?? null;
    $timeout === null || (is_int($timeout) && $timeout > 1) || throw new InvalidArgumentException(sprintf(
      'The profile has an invalid timeout value. Expected a positive integer greater than 0, got "%s".',
      gettype($timeout)
    ));
    $userVerification ??= $profile['user_verification'] ?? null;
    $userVerification === null || is_string($userVerification) || throw new InvalidArgumentException(sprintf(
      'The profile has an invalid attestation_conveyance value. Expected a string or null, got "%s".',
      gettype($userVerification)
    ));

    $options = PublicKeyCredentialRequestOptions::create(
      Base64UrlSafe::encode(random_bytes($profile['challenge_length'])),
      rpId: $rpId,
      allowCredentials: $allowCredentials,
      userVerification: $userVerification,
      timeout: $timeout,
      extensions: $AuthenticationExtensions ?? $this->createExtensions($profile)
    );

    return $options;
  }

  private function createExtensions(array $profile): AuthenticationExtensions
  {
    return AuthenticationExtensions::create(
      array_map(
        static fn (string $name, mixed $value): AuthenticationExtension => AuthenticationExtension::create(
          $name,
          $value
        ),
        array_keys($profile['extensions']),
        $profile['extensions']
      )
    );
  }

}
