package com.airlock.iam.admin.infrastructure.mapper.prot;

import com.airlock.iam.admin.infrastructure.transfer.response.user.tokens.FidoAttestationCertificateData;
import com.airlock.iam.admin.infrastructure.transfer.response.user.tokens.FidoAuthenticatorData;
import com.airlock.iam.admin.infrastructure.transfer.response.user.tokens.FidoPasswordlessCapabilityData;
import com.airlock.iam.admin.infrastructure.transfer.response.user.tokens.FidoUserCredentialData;
import com.airlock.iam.factor.domain.model.fido.FidoAuthenticatorInfo;
import com.airlock.iam.factor.domain.model.fido.FidoAuthenticatorModel;
import com.airlock.iam.factor.domain.model.fido.FidoPasswordlessCapability;
import com.airlock.iam.factor.domain.model.fido.FidoUserCredential;
import com.airlock.iam.factor.domain.model.fido.registration.FidoAttestationCertificate;
import ma.glasnost.orika.CustomMapper;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.MappingContext;

public class AdminFidoMapper {
   public AdminFidoMapper(MapperFactory factory) {
      this.configure(factory);
   }

   private void configure(MapperFactory factory) {
      factory.classMap(FidoUserCredential.class, FidoUserCredentialData.class).customize(new AdminFidoMapper.FidoUserCredentialMapper()).register();
   }

   private static final class FidoUserCredentialMapper extends CustomMapper<FidoUserCredential, FidoUserCredentialData> {
      public void mapAtoB(FidoUserCredential credential, FidoUserCredentialData credentialData, MappingContext context) {
         credentialData.setAccountDescriptor(credential.getName().getName());
         credential.getAttestationCertificate()
            .ifPresent(attestationCertificate -> credentialData.setAttestationCertificate(this.mapAttestationCertificate(attestationCertificate)));
         credential.getAuthenticatorInfo().ifPresent(authenticatorInfo -> credentialData.setAuthenticator(this.mapAuthenticatorInfo(authenticatorInfo)));
         credentialData.setDisplayName(credential.getDisplayName().getName());
         credential.firstUsedAt().ifPresent(credentialData::setFirstUsedAt);
         credential.lastUsedAt().ifPresent(credentialData::setLastUsedAt);
         credentialData.setLocked(credential.isLocked());
         credentialData.setTotalUsages(credential.totalUsages());
         credentialData.setPasswordless(this.mapPasswordlessCapability(credential.getPasswordless()));
         credentialData.setRegisteredAt(credential.getRegisteredAt());
         credentialData.setRelyingPartyId(credential.getRelyingPartyId().getId());
         credentialData.setTruncatedPublicKeyCredentialId(credential.getPublicKeyCredentialId().asTruncatedString());
      }

      private FidoAttestationCertificateData mapAttestationCertificate(FidoAttestationCertificate certificate) {
         return FidoAttestationCertificateData.builder()
            .certificate(certificate.base64Url())
            .subjectCommonName((String)certificate.subjectCommonName().orElse(null))
            .subjectOrganization((String)certificate.subjectOrganization().orElse(null))
            .build();
      }

      private FidoAuthenticatorData mapAuthenticatorInfo(FidoAuthenticatorInfo authenticatorInfo) {
         return new FidoAuthenticatorData(
            authenticatorInfo.getAaguid().toString(), authenticatorInfo.getModel().<String>map(FidoAuthenticatorModel::getModel).orElse(null)
         );
      }

      private FidoPasswordlessCapabilityData mapPasswordlessCapability(FidoPasswordlessCapability residentKey) {
         return residentKey.equals(FidoPasswordlessCapability.POSSIBLE) ? FidoPasswordlessCapabilityData.POSSIBLE : FidoPasswordlessCapabilityData.UNKNOWN;
      }
   }
}
