<?php

namespace Drupal\miniorange_webauthn\MoCredOptBuilder;

use Drupal\miniorange_webauthn\MoDto\MoPubKeyCredReqOptDto;
use Drupal\miniorange_webauthn\MoRepo\MoPubKeyCredSourceRepo;
use Drupal\miniorange_webauthn\MoRepo\MoPubKeyCredSourceRepoInterface;
use Drupal\miniorange_webauthn\MoRepo\MoPubKeyCredUserRepo;
use Drupal\miniorange_webauthn\MoService\MoPubKeyCredReqOptFactory;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
use Webauthn\AuthenticationExtensions\AuthenticationExtension;
use Webauthn\AuthenticationExtensions\AuthenticationExtensions;
use Webauthn\Bundle\Dto\ServerPublicKeyCredentialRequestOptionsRequest;
use Webauthn\PublicKeyCredentialDescriptor;
use Webauthn\PublicKeyCredentialRequestOptions;
use Webauthn\PublicKeyCredentialSource;
use Webauthn\PublicKeyCredentialUserEntity;

class MoProfileBasedReqOptBuilder implements MoProfileBasedReqOptBuilderInterface
{

  public function __construct(
    private readonly MoPubKeyCredReqOptDto $pubKeyCredReqOptDto,
    private readonly MoPubKeyCredUserRepo $userEntityRepository,
    private readonly MoPubKeyCredSourceRepoInterface $moPubKeyCredSourceRepo,
    private readonly MoPubKeyCredReqOptFactory $publicKeyCredentialRequestOptionsFactory
  )
  {
  }

  public function getFromRequest(
    Request $request,
  ): array {

//    $format = $request->getContentTypeFormat();
//    $format === 'json' || throw new BadRequestHttpException('Only JSON content type allowed');
    $optionsRequest = $this->getServerPublicKeyCredentialRequestOptionsRequest($request);

    $userEntity = $optionsRequest->getUsername() === null ? null : $this->userEntityRepository->findOneByUsername(
      $optionsRequest->getUsername()
    );

    $allowedCredentials = $this->getCredentials($userEntity);

    $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->publicKeyCredentialRequestOptionsFactory->create(
      $allowedCredentials,
      $optionsRequest->getUserVerification(),
      $extensions
    ), $userEntity];
  }

  private function getCredentials(PublicKeyCredentialUserEntity $userEntity): array
  {
    $credentialSources = $this->moPubKeyCredSourceRepo->findAllForUserEntity($userEntity);
    return array_map(
      static fn (PublicKeyCredentialSource $credential): PublicKeyCredentialDescriptor => $credential->getPublicKeyCredentialDescriptor(),
      $credentialSources
    );
  }

  private function getServerPublicKeyCredentialRequestOptionsRequest(
    Request $request,
  ):MoPubKeyCredReqOptDto  {
    $content = !empty($request->getContent()) ? $request->getContent() : $this->buildContent($request);
    return $this->pubKeyCredReqOptDto->buildFromJson($content);
  }

  private function buildContent(Request $request): false|string
  {
    $resp = [
      "username" => $request->get('username'),
      "userVerification" => "required",
      "extensions" => [
        "exampleExtension" => true
      ]
    ];
    return json_encode($resp);
  }
}
