package com.airlock.iam.authentication.domain.service.risk;

import com.airlock.iam.authentication.api.domain.model.risk.extractor.RiskExtractor;
import com.airlock.iam.authentication.api.domain.model.risk.extractor.RiskExtractorContext;
import com.airlock.iam.authentication.api.domain.model.risk.extractor.RiskTag;
import com.airlock.iam.authentication.domain.model.risk.RiskExtractorContextImpl;
import com.airlock.iam.authentication.domain.model.risk.RiskTags;
import com.airlock.iam.base.api.domain.model.user.UserId;
import com.airlock.iam.common.api.domain.model.loginhistory.LoginHistory;
import com.airlock.iam.common.api.domain.model.loginhistory.LoginHistoryEntry;
import com.airlock.iam.common.api.domain.model.request.RequestAttributes;
import com.airlock.iam.common.domain.model.loginhistory.LoginHistoryFilter;
import com.airlock.iam.common.domain.model.loginhistory.LoginHistoryImpl;
import com.airlock.iam.common.domain.model.loginhistory.LoginHistoryRepository;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;

public final class RiskExtractorServiceImpl implements RiskExtractorService {
   private final Provider<List<RiskExtractor>> riskExtractors;
   private final Provider<LoginHistoryRepository> loginHistoryRepository;

   @Inject
   public RiskExtractorServiceImpl(Provider<List<RiskExtractor>> riskExtractors, Provider<LoginHistoryRepository> loginHistoryRepository) {
      this.riskExtractors = riskExtractors;
      this.loginHistoryRepository = loginHistoryRepository;
   }

   @Override
   public RiskTags extractRiskTags(Optional<UserId> userId, RequestAttributes attributes) {
      if (((List)this.riskExtractors.get()).isEmpty()) {
         return new RiskTags();
      }

      List<LoginHistoryEntry> loginHistoryEntries = this.loadHistoryEntries(userId);
      Set<RiskTag> allRiskTags = new HashSet<>();

      for (RiskExtractor extractor : (List)this.riskExtractors.get()) {
         LoginHistory loginHistory = getHistoryOfMaxSize(loginHistoryEntries, extractor.getMaxLoginHistoryEntries());
         RiskExtractorContext context = new RiskExtractorContextImpl(userId, loginHistory, attributes);
         allRiskTags.addAll(extractor.extractRiskTags(context));
      }

      return new RiskTags(allRiskTags);
   }

   private List<LoginHistoryEntry> loadHistoryEntries(Optional<UserId> userId) {
      if (userId.isEmpty()) {
         return Collections.emptyList();
      }

      int numHistoryEntriesToLoad = ((List)this.riskExtractors.get()).stream().mapToInt(RiskExtractor::getMaxLoginHistoryEntries).max().orElse(0);
      return numHistoryEntriesToLoad == 0
         ? Collections.emptyList()
         : ((LoginHistoryRepository)this.loginHistoryRepository.get()).get(new LoginHistoryFilter(userId.get().getValue(), numHistoryEntriesToLoad));
   }

   private static LoginHistory getHistoryOfMaxSize(List<LoginHistoryEntry> loginHistoryEntries, int size) {
      return size >= loginHistoryEntries.size() ? new LoginHistoryImpl(loginHistoryEntries) : new LoginHistoryImpl(loginHistoryEntries.subList(0, size));
   }
}
