package com.airlock.iam.admin.application.configuration.locking;

import com.airlock.iam.admin.application.service.user.SessionLockBehavior;
import com.airlock.iam.admin.domain.model.LogTypes;
import com.airlock.iam.common.api.domain.model.persistency.exception.PersisterException;
import com.airlock.iam.common.api.domain.model.user.PersistentUser;
import com.airlock.iam.common.application.service.session.AirlockControlCookieService;
import com.airlock.iam.core.misc.persistency.UserPersister;
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.log.usertrail.UserTrailLogger;
import com.airlock.iam.plugin.api.annotation.config.Plugin;
import com.airlock.iam.plugin.api.annotation.property.PluginProperty;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Arrays;
import org.apache.commons.lang3.StringUtils;

@Plugin(
   description = "<p>Destroys currently active user sessions when the user is locked by an admin in the Adminapp.</p>\n<p>Note: This only works if the Adminapp is deployed behind the same Airlock Gateway (WAF) as the Loginapp.</p>"
)
public class DestroyLastUserSession implements SessionLockBehavior {
   private static final ELogger LOG = ELoggerFactory.getLogger(DestroyLastUserSession.class);
   @PluginProperty(
      description = "<p>Used to read and terminate the GSID (global session id) information of the locked user.</p>\n<p>Make sure that the selected user persister is configured for persisting the GSID.</p>",
      optional = false
   )
   private UserPersister userPersister;

   @Override
   public void handleUserLocked(String username, AirlockControlCookieService controlCookieService) {
      if (StringUtils.isBlank(username)) {
         LOG.debug("Not terminating session because username is missing.");
      } else {
         try {
            PersistentUser user = this.userPersister.getPersistentUserByName(username);
            String gsid = user.getLastKnownGlobalSessionID();
            if (StringUtils.isBlank(gsid)) {
               LOG.debug("Not terminating session because no GSID found.");
               return;
            }

            user.setLastKnownGlobalSessionID(null);
            user.setLastGlobalSessionIDUpdate(null);
            this.userPersister.makeUserPersistent(user);
            controlCookieService.terminateGSIDs(Arrays.asList(gsid));
            AuditLogger.log(LogTypes.ADMIN_ACTION_SAT, "Terminating session " + gsid + " of user \"" + username + "\" because of admin lock.");
            UserTrailLogger.log(username, "Terminating last session of user because of admin lock.");
         } catch (PersisterException e) {
            LOG.error(LogTypes.ADMIN_ACTION_SAT, "Cannot fetch user upon logout. Swallow exception to not interrupt logout", e);
         }
      }
   }

   @SuppressFBWarnings(justification = "generated code")
   public static DestroyLastUserSession.DestroyLastUserSessionBuilder builder() {
      return new DestroyLastUserSession.DestroyLastUserSessionBuilder();
   }

   @SuppressFBWarnings(justification = "generated code")
   public DestroyLastUserSession() {
   }

   @SuppressFBWarnings(justification = "generated code")
   public DestroyLastUserSession(UserPersister userPersister) {
      this.userPersister = userPersister;
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class DestroyLastUserSessionBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private UserPersister userPersister;

      @SuppressFBWarnings(justification = "generated code")
      DestroyLastUserSessionBuilder() {
      }

      @SuppressFBWarnings(justification = "generated code")
      public DestroyLastUserSession.DestroyLastUserSessionBuilder userPersister(UserPersister userPersister) {
         this.userPersister = userPersister;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public DestroyLastUserSession build() {
         return new DestroyLastUserSession(this.userPersister);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "DestroyLastUserSession.DestroyLastUserSessionBuilder(userPersister=" + this.userPersister + ")";
      }
   }
}
