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

import com.airlock.iam.base.api.domain.model.event.EventId;
import com.airlock.iam.base.api.domain.model.event.EventType;
import com.airlock.iam.base.api.domain.model.event.metadata.EventMetadata;
import com.airlock.iam.base.api.domain.model.event.source.EventSource;
import com.airlock.iam.base.api.domain.model.exception.FailureException;
import com.airlock.iam.base.api.domain.model.user.UserId;
import com.airlock.iam.base.domain.model.event.EventCreationData;
import com.airlock.iam.common.api.domain.model.authmethod.AuthenticationMethod;
import com.airlock.iam.common.api.domain.model.event.AuthenticationMethodChanged;
import com.airlock.iam.common.domain.model.event.CommonEventTypes;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.time.Instant;
import java.util.Optional;
import lombok.NonNull;

public final class AuthenticationMethodChangedImpl implements AuthenticationMethodChanged {
   @NonNull
   private final UserId userId;
   @NonNull
   private final Optional<AuthenticationMethod> activeAuthenticationMethod;
   @NonNull
   private final Optional<AuthenticationMethod> previousAuthenticationMethod;
   @NonNull
   private final EventCreationData eventCreationData;

   public AuthenticationMethodChangedImpl(
      @NonNull UserId userId,
      @NonNull Optional<AuthenticationMethod> activeAuthenticationMethod,
      @NonNull Optional<AuthenticationMethod> previousAuthenticationMethod,
      @NonNull EventCreationData eventCreationData
   ) {
      if (userId == null) {
         throw new NullPointerException("userId is marked non-null but is null");
      }

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

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

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

      FailureException.checkTrue(
         activeAuthenticationMethod.isPresent() || previousAuthenticationMethod.isPresent(),
         "event must either have an active and/or previous authentication method"
      );
      this.userId = userId;
      this.activeAuthenticationMethod = activeAuthenticationMethod;
      this.previousAuthenticationMethod = previousAuthenticationMethod;
      this.eventCreationData = eventCreationData;
   }

   @Override
   public EventId id() {
      return this.eventCreationData.id();
   }

   @Override
   public Instant createdAt() {
      return this.eventCreationData.createdAt();
   }

   @Override
   public EventSource source() {
      return this.eventCreationData.source();
   }

   @Override
   public EventMetadata metadata() {
      return this.eventCreationData.metadata();
   }

   @Override
   public String displayName() {
      return "Authentication Method Changed";
   }

   @Override
   public EventType type() {
      return CommonEventTypes.AUTHENTICATION_METHOD_CHANGED;
   }

   @NonNull
   @SuppressFBWarnings(justification = "generated code")
   @Override
   public UserId userId() {
      return this.userId;
   }

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

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

   @NonNull
   @SuppressFBWarnings(justification = "generated code")
   private EventCreationData eventCreationData() {
      return this.eventCreationData;
   }
}
