package com.airlock.iam.flow.shared.application.service;

import com.airlock.iam.base.misc.log.LogUtil;
import com.airlock.iam.common.domain.model.session.RemovedRole;
import com.airlock.iam.common.domain.service.request.AirlockEnvCookiesInformationService;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.flow.api.application.configuration.tag.TagConfig;
import com.airlock.iam.flow.api.domain.model.tag.Tag;
import com.airlock.iam.flow.api.domain.model.tag.TagName;
import com.airlock.iam.flow.shared.api.domain.model.session.UserSession;
import com.airlock.iam.flow.shared.application.configuration.RemovedRolesMapping;
import com.airlock.iam.flow.shared.domain.model.session.ProcessedRemovedRoles;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public final class RoleRemovalServiceImpl implements RoleRemovalService {
   private static final ELogger LOG = ELoggerFactory.getLogger(RoleRemovalServiceImpl.class);
   private final Provider<AirlockEnvCookiesInformationService> envCookieService;
   private final Provider<List<RemovedRolesMapping>> mappings;
   private final Provider<ProcessedRemovedRoles> processedRoles;

   @Inject
   public RoleRemovalServiceImpl(
      Provider<AirlockEnvCookiesInformationService> envCookieService,
      Provider<List<RemovedRolesMapping>> mappings,
      Provider<ProcessedRemovedRoles> processedRoles
   ) {
      this.envCookieService = envCookieService;
      this.mappings = mappings;
      this.processedRoles = processedRoles;
   }

   @Override
   public Set<Tag> removeTagsFromRemovedRoles(UserSession userSession) {
      if (((List)this.mappings.get()).isEmpty()) {
         return Collections.emptySet();
      }

      Set<Tag> removedTags = new HashSet<>();

      for (RemovedRole removedRole : this.removedRolesToProcess()) {
         Set<Tag> tagsRemovedFromRole = this.findTagsToRemove(removedRole)
            .stream()
            .flatMap(tag -> userSession.removeTagByName(tag).stream())
            .collect(Collectors.toSet());
         if (!tagsRemovedFromRole.isEmpty()) {
            LOG.debug(
               "Gateway removed role "
                  + LogUtil.quote(removedRole.roleName())
                  + " (because of "
                  + LogUtil.quote(removedRole.reason())
                  + "), which causes the removal of tags: "
                  + tagsRemovedFromRole
            );
            removedTags.addAll(tagsRemovedFromRole);
         }

         ((ProcessedRemovedRoles)this.processedRoles.get()).rememberRemovedRole(removedRole);
      }

      return removedTags;
   }

   private Set<RemovedRole> removedRolesToProcess() {
      return ((AirlockEnvCookiesInformationService)this.envCookieService.get())
         .getRemovedRoles()
         .stream()
         .filter(role -> !((ProcessedRemovedRoles)this.processedRoles.get()).isRemovedRoleProcessed(role))
         .collect(Collectors.toSet());
   }

   private Set<TagName> findTagsToRemove(RemovedRole removedRole) {
      return ((List)this.mappings.get())
         .stream()
         .filter(mapping -> mapping.getRoleName().equals(removedRole.roleName()))
         .flatMap(mapping -> mapping.getTags().stream())
         .map(TagConfig::name)
         .collect(Collectors.toSet());
   }
}
