package com.airlock.iam.login.misc.oneshot;

import com.airlock.iam.core.domain.model.authentication.factor.KnownAuthenticationFactor;
import com.airlock.iam.core.domain.model.authentication.method.KnownAuthenticationMethods;
import com.airlock.iam.core.misc.authen.Authentee;
import com.airlock.iam.core.misc.authen.AuthenticationSession;
import com.airlock.iam.core.misc.authen.Authenticator;
import com.airlock.iam.core.misc.authen.compatibility.AuthPluginContextValue;
import com.airlock.iam.core.misc.authen.compatibility.LegacyAuthPluginContextValue;
import com.airlock.iam.core.misc.authen.credential.Credential;
import com.airlock.iam.core.misc.authen.credential.SingleSignOnCredential;
import com.airlock.iam.core.misc.authen.result.AuthenticationFactorInfo;
import com.airlock.iam.core.misc.authen.result.AuthenticationFailed;
import com.airlock.iam.core.misc.authen.result.AuthenticationResult;
import com.airlock.iam.core.misc.authen.result.AuthenticationSuccessful;
import com.airlock.iam.core.misc.impl.authen.AuthenteeImpl;
import com.airlock.iam.core.misc.impl.authen.EmptyAuthenticationSession;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.plugin.api.annotation.config.Plugin;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

@Plugin(description = "Authenticates a user based on a Single-Sign-On-Credential.", displayName = "SSO Credential Authenticator")
public class SSOCredentialAuthenticator implements Authenticator {
   public static final String PLUGIN_DISPLAY_NAME = "SSO Credential Authenticator";
   private static final ELogger LOGGER = ELoggerFactory.getLogger(SSOCredentialAuthenticator.class);

   @Override
   public AuthenticationSession getAuthenticationSession() {
      return new EmptyAuthenticationSession();
   }

   @Override
   public AuthenticationResult authenticate(AuthenticationSession session, Credential credentials) {
      return this.addMetaDataToResult(this.authenticateInternal(credentials));
   }

   private AuthenticationResult authenticateInternal(Credential credentials) {
      if (!(credentials instanceof SingleSignOnCredential)) {
         LOGGER.info("Received wrong credential type. Received " + credentials.getClass() + " and expected " + SingleSignOnCredential.class + ".");
         return AuthenticationFailed.UNSPECIFIED.createResult();
      } else {
         return this.createAuthenteeFromCredential((SingleSignOnCredential)credentials);
      }
   }

   private AuthenticationResult addMetaDataToResult(AuthenticationResult result) {
      result.addValueToContextData("authPluginClassName", this.authPluginClassContextValue().contextValue());
      result.addValueToContextData("authMethodShortDesc", "SSO Credential Authenticator");
      result.initializeAuthenticationFactorInfoIfNotSet();
      result.setAuthenticationMethod(KnownAuthenticationMethods.TOKEN);
      return result;
   }

   @Override
   public AuthPluginContextValue authPluginClassContextValue() {
      return LegacyAuthPluginContextValue.SSO_CREDENTIAL_AUTHENTICATOR;
   }

   private AuthenticationResult createAuthenteeFromCredential(SingleSignOnCredential ssoCred) {
      Authentee authentee = new AuthenteeImpl(ssoCred.getUserName(), ssoCred.getUserRoles());

      for (String attribute : ssoCred.getAttributeKeys()) {
         authentee.getContextDataContainer().put(attribute, ssoCred.getAttributeValue(attribute));
      }

      AuthenticationSuccessful successfulResult = new AuthenticationSuccessful(authentee);
      return successfulResult.withAuthenticationFactorInfo(AuthenticationFactorInfo.successfulFactorInfo(KnownAuthenticationFactor.TOKEN));
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public static class SSOCredentialAuthenticatorBuilder {
      @SuppressFBWarnings(justification = "generated code")
      SSOCredentialAuthenticatorBuilder() {
      }

      @SuppressFBWarnings(justification = "generated code")
      public SSOCredentialAuthenticator build() {
         return new SSOCredentialAuthenticator();
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "SSOCredentialAuthenticator.SSOCredentialAuthenticatorBuilder()";
      }
   }
}
