package com.airlock.iam.authentication.impl.domain.model.step;

import com.airlock.iam.authentication.api.domain.model.step.AuthenticationStepResult;
import com.airlock.iam.authentication.api.domain.model.step.AuthenticationStepResultBuilder;
import com.airlock.iam.common.api.domain.model.authentication.factor.AuthenticationFactor;
import com.airlock.iam.common.api.domain.model.authentication.factor.AuthenticationFactorDetail;
import com.airlock.iam.common.api.domain.model.device.usage.AuthenticationDeviceUsage;
import com.airlock.iam.flow.api.domain.model.step.AdditionalAttributes;
import com.airlock.iam.flow.api.domain.model.step.InternalStepResultData;
import com.airlock.iam.flow.api.domain.model.step.StepAction;
import com.airlock.iam.flow.api.domain.model.step.StepError;
import com.airlock.iam.flow.api.domain.model.step.StepResult;
import com.airlock.iam.flow.api.domain.model.step.StepResultData;
import com.airlock.iam.flow.api.domain.model.tag.Tag;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import lombok.NonNull;

public final class AuthenticationStepResultImpl implements AuthenticationStepResult {
   @NonNull
   private final StepResult stepResult;
   @NonNull
   private final AuthenticationFactor authenticationFactor;
   @NonNull
   private final Optional<AuthenticationFactorDetail> authenticationFactorDetail;
   private final boolean isFailedFactor;
   @NonNull
   private final Optional<AuthenticationDeviceUsage> deviceUsageData;

   @Override
   public StepResult.StepResultType type() {
      return this.stepResult.type();
   }

   @Override
   public Optional<StepAction> nextAction() {
      return this.stepResult.nextAction();
   }

   @Override
   public Optional<StepError> error() {
      return this.stepResult.error();
   }

   @Override
   public boolean hasError(StepError expectedError) {
      return this.stepResult.hasError(expectedError);
   }

   @Override
   public Set<Tag> obtainedTags() {
      return this.stepResult.obtainedTags();
   }

   @Override
   public <T extends StepResultData> Optional<T> resultData() {
      return this.stepResult.resultData();
   }

   @Override
   public <T extends InternalStepResultData> Optional<T> internalResultData() {
      return this.stepResult.internalResultData();
   }

   @Override
   public Map<String, Object> metadata() {
      return this.stepResult.metadata();
   }

   @Override
   public AdditionalAttributes additionalAttributes() {
      return this.stepResult.additionalAttributes();
   }

   @Override
   public AuthenticationStepResultBuilder toBuilder() {
      AuthenticationStepResultBuilder builder = AuthenticationStepResultBuilderImpl.authenticationStepResultBuilder(this.stepResult.type());
      this.stepResult.nextAction().ifPresent(builder::nextAction);
      this.stepResult.error().ifPresent(builder::error);
      builder.obtainedTags(Set.copyOf(this.stepResult.obtainedTags()));
      this.stepResult.<StepResultData>resultData().ifPresent(builder::resultData);
      this.<InternalStepResultData>internalResultData().ifPresent(builder::internalResultData);
      builder.metadata(Map.copyOf(this.stepResult.metadata()));
      builder.additionalAttributes(this.stepResult.additionalAttributes().copy());
      builder.factor(this.authenticationFactor);
      builder.isFailedFactor(this.isFailedFactor);
      this.authenticationFactorDetail.ifPresent(builder::factorDetail);
      this.deviceUsageData.ifPresent(builder::deviceUsageData);
      return builder;
   }

   @SuppressFBWarnings(justification = "generated code")
   public AuthenticationStepResultImpl(
      @NonNull StepResult stepResult,
      @NonNull AuthenticationFactor authenticationFactor,
      @NonNull Optional<AuthenticationFactorDetail> authenticationFactorDetail,
      boolean isFailedFactor,
      @NonNull Optional<AuthenticationDeviceUsage> deviceUsageData
   ) {
      if (stepResult == null) {
         throw new NullPointerException("stepResult is marked non-null but is null");
      }

      if (authenticationFactor == null) {
         throw new NullPointerException("authenticationFactor is marked non-null but is null");
      }

      if (authenticationFactorDetail == null) {
         throw new NullPointerException("authenticationFactorDetail is marked non-null but is null");
      }

      if (deviceUsageData == null) {
         throw new NullPointerException("deviceUsageData is marked non-null but is null");
      }

      this.stepResult = stepResult;
      this.authenticationFactor = authenticationFactor;
      this.authenticationFactorDetail = authenticationFactorDetail;
      this.isFailedFactor = isFailedFactor;
      this.deviceUsageData = deviceUsageData;
   }

   @NonNull
   @SuppressFBWarnings(justification = "generated code")
   public StepResult getStepResult() {
      return this.stepResult;
   }

   @SuppressFBWarnings(justification = "generated code")
   @Override
   public boolean equals(Object o) {
      if (o == this) {
         return true;
      } else if (!(o instanceof AuthenticationStepResultImpl other)) {
         return false;
      } else {
         if (this.isFailedFactor != other.isFailedFactor) {
            return false;
         }

         Object this$stepResult = this.stepResult;
         Object other$stepResult = other.stepResult;
         if (this$stepResult == null ? other$stepResult == null : this$stepResult.equals(other$stepResult)) {
            Object this$authenticationFactor = this.authenticationFactor;
            Object other$authenticationFactor = other.authenticationFactor;
            if (this$authenticationFactor == null ? other$authenticationFactor == null : this$authenticationFactor.equals(other$authenticationFactor)) {
               Object this$authenticationFactorDetail = this.authenticationFactorDetail;
               Object other$authenticationFactorDetail = other.authenticationFactorDetail;
               if (this$authenticationFactorDetail == null
                  ? other$authenticationFactorDetail == null
                  : this$authenticationFactorDetail.equals(other$authenticationFactorDetail)) {
                  Object this$deviceUsageData = this.deviceUsageData;
                  Object other$deviceUsageData = other.deviceUsageData;
                  return this$deviceUsageData == null ? other$deviceUsageData == null : this$deviceUsageData.equals(other$deviceUsageData);
               } else {
                  return false;
               }
            } else {
               return false;
            }
         } else {
            return false;
         }
      }
   }

   @SuppressFBWarnings(justification = "generated code")
   @Override
   public int hashCode() {
      int PRIME = 59;
      int result = 1;
      result = result * 59 + (this.isFailedFactor ? 79 : 97);
      Object $stepResult = this.stepResult;
      result = result * 59 + ($stepResult == null ? 43 : $stepResult.hashCode());
      Object $authenticationFactor = this.authenticationFactor;
      result = result * 59 + ($authenticationFactor == null ? 43 : $authenticationFactor.hashCode());
      Object $authenticationFactorDetail = this.authenticationFactorDetail;
      result = result * 59 + ($authenticationFactorDetail == null ? 43 : $authenticationFactorDetail.hashCode());
      Object $deviceUsageData = this.deviceUsageData;
      return result * 59 + ($deviceUsageData == null ? 43 : $deviceUsageData.hashCode());
   }

   @SuppressFBWarnings(justification = "generated code")
   @Override
   public String toString() {
      return "AuthenticationStepResultImpl(stepResult="
         + this.getStepResult()
         + ", authenticationFactor="
         + this.getAuthenticationFactor()
         + ", authenticationFactorDetail="
         + this.getAuthenticationFactorDetail()
         + ", isFailedFactor="
         + this.isFailedFactor()
         + ", deviceUsageData="
         + this.getDeviceUsageData()
         + ")";
   }

   @NonNull
   @SuppressFBWarnings(justification = "generated code")
   @Override
   public AuthenticationFactor getAuthenticationFactor() {
      return this.authenticationFactor;
   }

   @NonNull
   @SuppressFBWarnings(justification = "generated code")
   @Override
   public Optional<AuthenticationFactorDetail> getAuthenticationFactorDetail() {
      return this.authenticationFactorDetail;
   }

   @SuppressFBWarnings(justification = "generated code")
   @Override
   public boolean isFailedFactor() {
      return this.isFailedFactor;
   }

   @NonNull
   @SuppressFBWarnings(justification = "generated code")
   @Override
   public Optional<AuthenticationDeviceUsage> getDeviceUsageData() {
      return this.deviceUsageData;
   }
}
