package com.airlock.iam.common.domain.model.user;

import com.airlock.iam.base.api.domain.model.exception.FailureException;
import com.airlock.iam.base.api.domain.model.exception.ServiceConfigurationException;
import com.airlock.iam.base.misc.log.LogUtil;
import com.airlock.iam.common.api.domain.model.contextdata.ContextDataItem;
import com.airlock.iam.common.api.domain.model.user.User;
import com.airlock.iam.core.domain.model.user.UserToPropagatedNameTransformer;
import com.airlock.iam.core.domain.model.user.UsernameTransformationResult;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils;

public class UserToContextDataTransformer implements UserToPropagatedNameTransformer {
   private final String contextDataField;
   private final boolean mandatoryTransformation;
   private final boolean stopAfterSuccessfulTransformation;

   @Override
   public UsernameTransformationResult transformToPropagatedName(String username, User user) {
      Optional<String> contextDataValue = this.contextDataValue(user);
      if (contextDataValue.isEmpty()) {
         if (this.mandatoryTransformation) {
            throw new FailureException(
               String.format("Cannot transform userid %s; context data field %s is null or empty.", LogUtil.quote(user.getName()), this.contextDataField)
            );
         } else {
            return UsernameTransformationResult.createNotMatchedResult();
         }
      } else {
         return new UsernameTransformationResult(contextDataValue.get(), this.stopAfterSuccessfulTransformation);
      }
   }

   private Optional<String> contextDataValue(User user) {
      return user.getContextData().find(this.contextDataField).map(ContextDataItem::getValue).flatMap(this::trimmedStringValue);
   }

   private Optional<String> trimmedStringValue(Object o) {
      if (o instanceof String) {
         return Optional.ofNullable(StringUtils.trimToNull((String)o));
      } else {
         throw new ServiceConfigurationException(
            "Configured context data field "
               + LogUtil.quote(this.contextDataField)
               + " is not of type String but of type "
               + LogUtil.quote(o.getClass().getName())
         );
      }
   }

   @SuppressFBWarnings(justification = "generated code")
   static UserToContextDataTransformer.UserToContextDataTransformerBuilder builder() {
      return new UserToContextDataTransformer.UserToContextDataTransformerBuilder();
   }

   @SuppressFBWarnings(justification = "generated code")
   public UserToContextDataTransformer(String contextDataField, boolean mandatoryTransformation, boolean stopAfterSuccessfulTransformation) {
      this.contextDataField = contextDataField;
      this.mandatoryTransformation = mandatoryTransformation;
      this.stopAfterSuccessfulTransformation = stopAfterSuccessfulTransformation;
   }

   @SuppressFBWarnings(justification = "generated code")
   static class UserToContextDataTransformerBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private String contextDataField;
      @SuppressFBWarnings(justification = "generated code")
      private boolean mandatoryTransformation;
      @SuppressFBWarnings(justification = "generated code")
      private boolean stopAfterSuccessfulTransformation;

      @SuppressFBWarnings(justification = "generated code")
      UserToContextDataTransformer.UserToContextDataTransformerBuilder contextDataField(String contextDataField) {
         this.contextDataField = contextDataField;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      UserToContextDataTransformer.UserToContextDataTransformerBuilder mandatoryTransformation(boolean mandatoryTransformation) {
         this.mandatoryTransformation = mandatoryTransformation;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      UserToContextDataTransformer.UserToContextDataTransformerBuilder stopAfterSuccessfulTransformation(boolean stopAfterSuccessfulTransformation) {
         this.stopAfterSuccessfulTransformation = stopAfterSuccessfulTransformation;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      UserToContextDataTransformer build() {
         return new UserToContextDataTransformer(this.contextDataField, this.mandatoryTransformation, this.stopAfterSuccessfulTransformation);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "UserToContextDataTransformer.UserToContextDataTransformerBuilder(contextDataField="
            + this.contextDataField
            + ", mandatoryTransformation="
            + this.mandatoryTransformation
            + ", stopAfterSuccessfulTransformation="
            + this.stopAfterSuccessfulTransformation
            + ")";
      }
   }
}
