<?php

namespace Drupal\miniorange_webauthn\MoDto;

use InvalidArgumentException;
use Webauthn\PublicKeyCredentialRequestOptions;

class MoPubKeyCredReqOptDto
{
  private ?string $username = null;

  private ?string $userVerification = null;

  /**
   * @var array<string, mixed>|null
   */
  private ?array $extensions = null;

  public function getUsername(): ?string
  {
    return $this->username;
  }

  public function setUsername(?string $username): self
  {
    $this->username = $username;
    return $this;
  }

  public function getUserVerification(): ?string
  {
    return $this->userVerification;
  }

  public function setUserVerification(?string $userVerification): self
  {
    $this->userVerification = $userVerification;
    return $this;
  }

  /**
   * @return array<string, mixed>|null
   */
  public function getExtensions(): ?array
  {
    return $this->extensions;
  }

  /**
   * @param array<string, mixed>|null $extensions
   */
  public function setExtensions(?array $extensions): self
  {
    $this->extensions = $extensions;
    return $this;
  }

  public function validate($context): array
  {
    // Validate username: allow null but not empty string
    if ($this->getUsername() !== null && trim($this->getUsername()) === '') {
      $error['username'] = 'Username cannot be empty or whitespace.';
    }

    // Validate userVerification: must be one of the predefined constants or null
    $allowedValues = [
      PublicKeyCredentialRequestOptions::USER_VERIFICATION_REQUIREMENT_PREFERRED,
      PublicKeyCredentialRequestOptions::USER_VERIFICATION_REQUIREMENT_REQUIRED,
      PublicKeyCredentialRequestOptions::USER_VERIFICATION_REQUIREMENT_DISCOURAGED,
    ];

    if ($this->getUserVerification() !== null && !in_array($this->getUserVerification(), $allowedValues, true)) {
      $error['userVerification'] = 'Invalid user verification value.';
    }

    // Validate extensions: must be an array if not null
    if ($this->getExtensions() !== null && !is_array($this->getExtensions())) {
      $error['extensions'] = 'Extensions must be an array.';
    }
    return $error ?? [];
  }

  public function buildFromJson(string $json)
  {
    $decoded = json_decode($json, true);
    if (json_last_error() !== JSON_ERROR_NONE) {
      throw new \InvalidArgumentException('Invalid JSON provided.');
    }
    $dto = new self();
    $dto->setUsername($decoded['username'] ?? null);
    $dto->setUserVerification($decoded['userVerification'] ?? null);
    $dto->setExtensions(isset($decoded['extensions']) && is_array($decoded['extensions']) ? $decoded['extensions'] : null);

    if (!empty($errors = $dto->validate($dto))) {
      foreach ($errors as $field => $message) {
        $messages[] = $field . ': ' . $message;
      }
      throw new InvalidArgumentException(implode("\n", $messages ?? []));
    }
    return $dto;
  }
}
