package com.airlock.iam.login.app.misc.session;

import com.airlock.iam.common.api.domain.model.role.Role;
import com.airlock.iam.core.misc.authen.Authentee;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.log.audit.AuditLogger;
import com.airlock.iam.login.app.misc.configuration.UserSpecificRoleTimeoutDefinition;
import com.airlock.iam.login.application.configuration.targetapp.RoleTimeoutRuleConfig;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.annotation.Nullable;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class UserSpecificRoleTimeoutCalculator {
   private static final ELogger LOGGER = ELoggerFactory.getLogger(UserSpecificRoleTimeoutCalculator.class);
   private final List<UserSpecificRoleTimeoutDefinition> userSpecificRoleTimeoutDefinitionList;

   public void updateRoleTimeouts(Authentee authentee) {
      if (this.userSpecificRoleTimeoutDefinitionList != null && !this.userSpecificRoleTimeoutDefinitionList.isEmpty()) {
         Map<String, Object> contextDataContainer = authentee.getContextDataContainer();
         String[] roleNames = authentee.getGrantedRoleNames();

         for (String role : roleNames) {
            Optional<UserSpecificRoleTimeoutDefinition> userSpecificRoleTimeoutDefinition = this.getUserSpecificRoleTimeoutDefinition(role);
            if (!userSpecificRoleTimeoutDefinition.isEmpty()) {
               String timeoutId = (String)contextDataContainer.get(userSpecificRoleTimeoutDefinition.get().getContextDataProperty());
               Optional<RoleTimeoutRuleConfig> roleTimeoutRule = this.getRoleTimeoutRule(userSpecificRoleTimeoutDefinition.get(), timeoutId);
               if (roleTimeoutRule.isPresent()) {
                  LOGGER.debug(
                     "Applying role timeout rule "
                        + roleTimeoutRule.get().getTimeoutIdentifier()
                        + " with timeout "
                        + roleTimeoutRule.get().getIdleTimeout()
                        + " and lifeTime "
                        + roleTimeoutRule.get().getLifetime()
                  );
                  this.changeAuthenteeRole(authentee, role, roleTimeoutRule.get().getIdleTimeout(), roleTimeoutRule.get().getLifetime());
               } else {
                  LOGGER.debug(
                     "Applying default timeout rule, with timeout "
                        + userSpecificRoleTimeoutDefinition.get().getDefaultIdleTimeout()
                        + " and lifeTime "
                        + userSpecificRoleTimeoutDefinition.get().getDefaultLifeTime()
                  );
                  this.changeAuthenteeRole(
                     authentee,
                     role,
                     userSpecificRoleTimeoutDefinition.get().getDefaultIdleTimeout(),
                     userSpecificRoleTimeoutDefinition.get().getDefaultLifeTime()
                  );
               }
            }
         }
      }
   }

   private Optional<RoleTimeoutRuleConfig> getRoleTimeoutRule(UserSpecificRoleTimeoutDefinition userSpecificRoleTimeoutDefinition, @Nullable String timeoutId) {
      for (RoleTimeoutRuleConfig roleTimeoutRule : userSpecificRoleTimeoutDefinition.getRoleTimeoutRules()) {
         if (roleTimeoutRule.getTimeoutIdentifier().equals(timeoutId)) {
            return Optional.of(roleTimeoutRule);
         }
      }

      return Optional.empty();
   }

   private Optional<UserSpecificRoleTimeoutDefinition> getUserSpecificRoleTimeoutDefinition(String role) {
      for (UserSpecificRoleTimeoutDefinition userSpecificRoleTimeoutDefinition : this.userSpecificRoleTimeoutDefinitionList) {
         if (userSpecificRoleTimeoutDefinition.getRole().equals(Role.parseRole(role).getRoleName())) {
            return Optional.of(userSpecificRoleTimeoutDefinition);
         }
      }

      return Optional.empty();
   }

   private void changeAuthenteeRole(Authentee authentee, String role, int idleTimeout, @Nullable Integer lifeTime) {
      Role newRole = Role.parseRole(role).withoutTimeouts().withIdleTimeout(idleTimeout);
      if (lifeTime != null) {
         newRole = newRole.withLifetime(lifeTime);
      }

      authentee.removeRole(role);
      authentee.addGrantedRoleName(newRole.formatRole());
      AuditLogger.log(this.getClass(), "Replacing role \"" + role + "\" with new role \"" + newRole + "\" based on user-specific role-timeout settings.");
   }

   @SuppressFBWarnings(justification = "generated code")
   public UserSpecificRoleTimeoutCalculator(List<UserSpecificRoleTimeoutDefinition> userSpecificRoleTimeoutDefinitionList) {
      this.userSpecificRoleTimeoutDefinitionList = userSpecificRoleTimeoutDefinitionList;
   }
}
