package com.airlock.iam.publicselfservice.infrastructure.mapper.converter;

import com.airlock.iam.factor.domain.model.fido.FidoPublicKeyCredentialRequestOptions;
import com.airlock.iam.factor.domain.model.fido.registration.FidoUserVerificationPreference;
import com.airlock.iam.fido.api.domain.model.FidoPublicKeyCredentialId;
import com.airlock.iam.flow.shared.domain.model.fido.FidoPublicKeyCredentialRequestOptionData;
import com.airlock.iam.flow.shared.infrastructure.transfer.response.fido.FidoCredentialAllowedTransportData;
import com.airlock.iam.flow.shared.infrastructure.transfer.response.fido.FidoPublicKeyCredentialRequestOptionsData;
import com.airlock.iam.flow.shared.infrastructure.transfer.response.fido.FidoUserVerificationPreferenceData;
import com.airlock.iam.flow.shared.infrastructure.transfer.response.fido.PublicKeyCredentialDescriptorData;
import com.airlock.iam.publicselfservice.infrastructure.transfer.PublicSelfServiceFidoApprovalChallengeData;
import java.util.Collections;
import java.util.stream.Collectors;
import ma.glasnost.orika.CustomConverter;
import ma.glasnost.orika.MappingContext;
import ma.glasnost.orika.metadata.Type;

public final class FidoApprovalChallengeConverter extends CustomConverter<FidoPublicKeyCredentialRequestOptionData, PublicSelfServiceFidoApprovalChallengeData> {
   public PublicSelfServiceFidoApprovalChallengeData convert(
      FidoPublicKeyCredentialRequestOptionData source,
      Type<? extends PublicSelfServiceFidoApprovalChallengeData> destinationType,
      MappingContext mappingContext
   ) {
      FidoPublicKeyCredentialRequestOptions options = source.options();
      return PublicSelfServiceFidoApprovalChallengeData.builder()
         .publicKeyCredentialRequestOptions(
            FidoPublicKeyCredentialRequestOptionsData.builder()
               .rpId(options.getRelyingPartyId().getId())
               .challenge(options.getChallenge().base64Url())
               .timeout(options.getAuthenticationSettings().authenticationTimeout().toMillis())
               .userVerification(map(options.getAuthenticationSettings().userVerification()))
               .allowCredentials(
                  options.getAllowedCredentialIds()
                     .map(
                        allowedCredentialIds -> allowedCredentialIds.stream()
                           .map(FidoPublicKeyCredentialId::base64Url)
                           .map(
                              id -> PublicKeyCredentialDescriptorData.publicKeyCredentialDescriptorData(
                                 id,
                                 options.getAuthenticationSettings()
                                    .transports()
                                    .stream()
                                    .map(t -> FidoCredentialAllowedTransportData.fromString(t.getValue()))
                                    .collect(Collectors.toSet())
                              )
                           )
                           .toList()
                     )
                     .orElse(Collections.emptyList())
               )
               .build()
         )
         .build();
   }

   private static FidoUserVerificationPreferenceData map(FidoUserVerificationPreference userVerification) {
      return switch (userVerification) {
         case REQUIRED -> FidoUserVerificationPreferenceData.REQUIRED;
         case PREFERRED -> FidoUserVerificationPreferenceData.PREFERRED;
         case DISCOURAGED -> FidoUserVerificationPreferenceData.DISCOURAGED;
      };
   }
}
