package com.airlock.iam.flow.shared.domain.model.condition;

import com.airlock.iam.base.api.domain.model.plugin.LogicForConfig;
import com.airlock.iam.base.api.domain.model.user.UserId;
import com.airlock.iam.common.domain.model.user.PrincipalInfo;
import com.airlock.iam.core.misc.impl.token.cronto.CrontoDeviceToken;
import com.airlock.iam.core.misc.token.Token;
import com.airlock.iam.flow.api.domain.model.step.FlowCondition;
import com.airlock.iam.flow.shared.application.configuration.condition.HasCrontoDeviceConditionConfig;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.util.List;

@LogicForConfig(HasCrontoDeviceConditionConfig.class)
public final class CrontoCredentialCondition implements FlowCondition {
   private final Provider<PrincipalInfo> user;
   private final HasCrontoDeviceConditionConfig config;

   @Inject
   public CrontoCredentialCondition(Provider<PrincipalInfo> user, HasCrontoDeviceConditionConfig config) {
      this.user = user;
      this.config = config;
   }

   @Override
   public boolean isFulfilled() {
      UserId userId = ((PrincipalInfo)this.user.get()).getKnownIdentity().orElseThrow().id();
      return this.config.isRequirePushDevice() ? this.hasActivePushDevice(userId) : this.hasActiveDevice(userId);
   }

   private boolean hasActiveDevice(UserId userId) {
      return this.config.getCrontoHandler().hasActiveToken(userId);
   }

   private boolean hasActivePushDevice(UserId userId) {
      return this.containsActiveDevice(this.loadPushDevicesForUser(userId));
   }

   private boolean containsActiveDevice(List<CrontoDeviceToken> devices) {
      return devices.stream().anyMatch(Token::isActive);
   }

   private List<CrontoDeviceToken> loadPushDevicesForUser(UserId userId) {
      return this.config.getCrontoHandler().getPushAppHandler().getPushEnabledDevices(userId);
   }

   @Override
   public String displayName() {
      return "Has Cronto Device";
   }
}
