package com.airlock.iam.admin.application.service.token.generic;

import com.airlock.iam.admin.api.domain.model.token.generic.GenericToken;
import com.airlock.iam.base.misc.util.Base64Util;
import com.airlock.iam.core.misc.impl.persistency.CredentialData;
import com.airlock.iam.core.misc.persistency.CredentialBean;
import com.airlock.iam.core.misc.persistency.CredentialBean.CredentialDataEncoding;
import com.airlock.iam.core.misc.util.DateRange;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

public class CredentialBasedGenericTokenConverter {
   public static final String DELIVERY_DATE = "deliveryDate";
   public static final String GENERATION_DATE = "generationDate";
   public static final String SERIAL_NUMBER = "serialNumber";
   public static final String ACTIVE = "active";
   public static final String VALID_FROM = "validFrom";
   public static final String VALID_TO = "validTo";
   public static final String ENCODING = "encoding";
   public static final String DATA = "data";
   public static final String CONTEXT_DATA = "contextData";

   public GenericToken mapToToken(CredentialData credentialData, CredentialBean credentialBean, String username, String tokenId) {
      Map<String, Object> map = new HashMap<>();
      map.put("deliveryDate", credentialData.getDeliveryDate());
      map.put("generationDate", credentialData.getGenerationDate());
      map.put("serialNumber", credentialData.getSerialNumber());
      map.put("data", this.getTokenDataAsString(credentialData));
      map.put("encoding", credentialData.getEncoding().name());
      map.put("active", credentialBean.isActive());
      map.put("validFrom", credentialData.getValidityRange().getFromDate());
      map.put("validTo", credentialData.getValidityRange().getToDate());
      map.put("contextData", credentialBean.getContextDataContainer());
      GenericToken.GenericTokenBuilder tokenBuilder = GenericToken.builder()
         .currentUserName(Optional.of(username))
         .mappedAttributes(map)
         .tokenId(tokenId)
         .previousTokenId(Optional.empty())
         .nextTokenIds(Collections.emptyList())
         .tokenDataKey("data");
      if (CredentialTokens.isCurrentId(tokenId) && CredentialTokens.isNextVisible(credentialBean.getNext())) {
         tokenBuilder.nextTokenIds(Collections.singletonList(CredentialTokens.nextId(username)));
      }

      if (CredentialTokens.isNextId(tokenId)) {
         tokenBuilder.previousTokenId(Optional.of(CredentialTokens.currentId(username)));
      }

      return tokenBuilder.build();
   }

   public CredentialData mapToCredentialData(GenericToken token) {
      CredentialData credentialData = new CredentialData();
      credentialData.setDeliveryDate(token.getAttribute("deliveryDate"));
      credentialData.setGenerationDate(token.getAttribute("generationDate"));
      credentialData.setSerialNumber(token.getAttribute("serialNumber"));
      credentialData.setValidityRange(DateRange.of(token.getAttribute("validFrom"), token.getAttribute("validTo")));
      if (this.isBinaryData(token)) {
         if (token.getAttribute("data") == null) {
            credentialData.setData((byte[])null);
         } else {
            credentialData.setData(Base64Util.decode(token.getAttribute("data")));
         }
      } else {
         credentialData.setData(token.getAttribute("data"));
      }

      return credentialData;
   }

   private boolean isBinaryData(GenericToken token) {
      return CredentialDataEncoding.BINARY.name().equals(token.getAttribute("encoding"));
   }

   private String getTokenDataAsString(CredentialData credentialData) {
      if (credentialData.getEncoding().equals(CredentialDataEncoding.STRING)) {
         return credentialData.getStringData();
      } else {
         return credentialData.getBinaryData() == null ? null : Base64Util.encodeToString(credentialData.getBinaryData());
      }
   }
}
