<?php

namespace Drupal\miniorange_webauthn\MoCredOptBuilder;

use Drupal\miniorange_webauthn\MoDto\MoPubKeyCredCreateOptionReqDto;
use Drupal\miniorange_webauthn\MoRepo\MoPubKeyCredSourceRepoInterface;
use Drupal\miniorange_webauthn\MoService\MoPubKeyCredCreateOptFactory;
use Symfony\Component\HttpFoundation\Request;

use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Webauthn\AuthenticationExtensions\AuthenticationExtension;
use Webauthn\AuthenticationExtensions\AuthenticationExtensions;
use Webauthn\AuthenticatorSelectionCriteria;
use Webauthn\PublicKeyCredentialCreationOptions;
use Webauthn\PublicKeyCredentialDescriptor;
use Webauthn\PublicKeyCredentialSource;
use Webauthn\PublicKeyCredentialUserEntity;


class MoPubKeyCredCreateOptionBuilder implements MoPubKeyCredCreateOptBuildInterface
{

  public function __construct(
    private MoPubKeyCredCreateOptionReqDto  $optionsDto,
    Private MoPubKeyCredSourceRepoInterface $pubKeyCredSourceRepo,
    private MoPubKeyCredCreateOptFactory $createOptFactory
  )
  {
  }

  public function getFromRequest(
    Request $request,
    PublicKeyCredentialUserEntity $userEntity
  ): PublicKeyCredentialCreationOptions {
    $format = $request->getContentTypeFormat();

//    $format === 'json' || throw new BadRequestHttpException('Only JSON content type allowed');
    $content = !empty($request->getContent()) ? $request->getContent() : $this->buildContent();

    $excludedCredentials = $this->getPubKeyCredentials($userEntity);
    $optionsRequest = $this->getPubKeyCredCreateOptReq($content);

    $residentKey = $optionsRequest->getResidentKey() ?? null;


    $authenticatorSelection = AuthenticatorSelectionCriteria::create(
      $optionsRequest->getAuthenticatorAttachment(),
      $optionsRequest->getUserVerification() ?? AuthenticatorSelectionCriteria::USER_VERIFICATION_REQUIREMENT_PREFERRED,
      $residentKey,
    );

    $extensions = null;
    if (is_array($optionsRequest->getExtensions())) {
      $extensions = AuthenticationExtensions::create(array_map(
        static fn (string $name, mixed $data): AuthenticationExtension => AuthenticationExtension::create(
          $name,
          $data
        ),
        array_keys($optionsRequest->getExtensions()),
        $optionsRequest->getExtensions()
      ));
    }

    return $this->createOptFactory->create(
      $userEntity,
      $excludedCredentials,
      $authenticatorSelection,
      $optionsRequest->attestation,
      $extensions
    );
  }

  private function getPubKeyCredentials(PublicKeyCredentialUserEntity $userEntity): array
  {
    $credentialSources = $this->pubKeyCredSourceRepo->findAllForUserEntity($userEntity);

    return array_map(
      static fn (PublicKeyCredentialSource $credential): PublicKeyCredentialDescriptor => $credential->getPublicKeyCredentialDescriptor(),
      $credentialSources
    );
  }

  private function getPubKeyCredCreateOptReq(
    string $content
  ): MoPubKeyCredCreateOptionReqDto {

    return $this->optionsDto->buildDtoFromJson($content);
  }

  private function buildContent()
  {
    $resp = [
      "attestation" => "direct",
      "userVerification" => "required",
      "residentKey" => "preferred",
      // "authenticatorAttachment" => "platform",
      "extensions" => [
        "exampleExtension" => true
      ]
    ];
    return json_encode($resp);
  }
}
