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

import com.airlock.iam.authentication.domain.model.rememberme.RememberMeRequest;
import com.airlock.iam.authentication.domain.model.rememberme.RememberMeResponse;
import com.airlock.iam.base.api.domain.model.user.UserId;
import com.airlock.iam.base.misc.log.LogUtil;
import com.airlock.iam.common.api.domain.model.user.UserIdentity;
import com.airlock.iam.common.application.configuration.rememberme.RememberMeConfig;
import com.airlock.iam.common.domain.model.user.PrincipalInfo;
import com.airlock.iam.flow.shared.domain.model.rememberme.RememberMeSecret;
import com.airlock.iam.flow.shared.domain.model.rememberme.RememberMeSecretHash;
import com.airlock.iam.flow.shared.domain.model.rememberme.RememberMeTokenRepository;
import com.airlock.iam.log.api.helpdesk.HelpdeskLogger;
import com.airlock.iam.log.api.signing.SigningLogger;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.util.Optional;

public class RememberMeLogoutServiceImpl implements RememberMeLogoutService {
   private final RememberMeConfig.LogoutBehaviour logoutBehaviour;
   private final Provider<RememberMeRequest> request;
   private final Provider<RememberMeResponse> response;
   private final Provider<RememberMeTokenRepository> tokenRepository;
   private final Provider<PrincipalInfo> principalInfo;
   private final SigningLogger signingLogger;
   private final HelpdeskLogger helpdeskLogger;

   @Inject
   public RememberMeLogoutServiceImpl(
      RememberMeConfig.LogoutBehaviour logoutBehaviour,
      Provider<RememberMeRequest> request,
      Provider<RememberMeResponse> response,
      Provider<RememberMeTokenRepository> tokenRepository,
      Provider<PrincipalInfo> principalInfo,
      SigningLogger signingLogger,
      HelpdeskLogger helpdeskLogger
   ) {
      this.logoutBehaviour = logoutBehaviour;
      this.request = request;
      this.response = response;
      this.tokenRepository = tokenRepository;
      this.principalInfo = principalInfo;
      this.signingLogger = signingLogger;
      this.helpdeskLogger = helpdeskLogger;
   }

   @Override
   public void logout() {
      if (this.logoutBehaviour == RememberMeConfig.LogoutBehaviour.REMOVE_COOKIE) {
         Optional<RememberMeSecret> secret = ((RememberMeRequest)this.request.get()).findRememberMeSecret();
         if (secret.isPresent()) {
            ((RememberMeResponse)this.response.get()).deleteRememberMeCookie();
            RememberMeSecretHash hash = secret.get().hash();
            ((RememberMeTokenRepository)this.tokenRepository.get()).deleteBy(hash);
            Optional<UserId> userId = ((PrincipalInfo)this.principalInfo.get()).getKnownIdentity().map(UserIdentity::id);
            this.logCookieDeletion(userId, hash);
         }
      }
   }

   private void logCookieDeletion(Optional<UserId> userId, RememberMeSecretHash hash) {
      String message = String.format("Deleted Remember-Me cookie and token with hash %s for unknown user.", LogUtil.logSafeQuote(hash));
      if (userId.isPresent()) {
         message = String.format(
            "Deleted Remember-Me cookie and token with hash %s for user %s.", LogUtil.logSafeQuote(hash), LogUtil.logSafeQuote(userId.get().getValue())
         );
         this.helpdeskLogger.log(userId.get().getValue(), message);
      }

      this.signingLogger.log(message);
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public static class RememberMeLogoutServiceImplBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private RememberMeConfig.LogoutBehaviour logoutBehaviour;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<RememberMeRequest> request;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<RememberMeResponse> response;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<RememberMeTokenRepository> tokenRepository;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<PrincipalInfo> principalInfo;
      @SuppressFBWarnings(justification = "generated code")
      private SigningLogger signingLogger;
      @SuppressFBWarnings(justification = "generated code")
      private HelpdeskLogger helpdeskLogger;

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

      @SuppressFBWarnings(justification = "generated code")
      public RememberMeLogoutServiceImpl.RememberMeLogoutServiceImplBuilder logoutBehaviour(RememberMeConfig.LogoutBehaviour logoutBehaviour) {
         this.logoutBehaviour = logoutBehaviour;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public RememberMeLogoutServiceImpl.RememberMeLogoutServiceImplBuilder request(Provider<RememberMeRequest> request) {
         this.request = request;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public RememberMeLogoutServiceImpl.RememberMeLogoutServiceImplBuilder response(Provider<RememberMeResponse> response) {
         this.response = response;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public RememberMeLogoutServiceImpl.RememberMeLogoutServiceImplBuilder tokenRepository(Provider<RememberMeTokenRepository> tokenRepository) {
         this.tokenRepository = tokenRepository;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public RememberMeLogoutServiceImpl.RememberMeLogoutServiceImplBuilder principalInfo(Provider<PrincipalInfo> principalInfo) {
         this.principalInfo = principalInfo;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public RememberMeLogoutServiceImpl.RememberMeLogoutServiceImplBuilder signingLogger(SigningLogger signingLogger) {
         this.signingLogger = signingLogger;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public RememberMeLogoutServiceImpl.RememberMeLogoutServiceImplBuilder helpdeskLogger(HelpdeskLogger helpdeskLogger) {
         this.helpdeskLogger = helpdeskLogger;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public RememberMeLogoutServiceImpl build() {
         return new RememberMeLogoutServiceImpl(
            this.logoutBehaviour, this.request, this.response, this.tokenRepository, this.principalInfo, this.signingLogger, this.helpdeskLogger
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "RememberMeLogoutServiceImpl.RememberMeLogoutServiceImplBuilder(logoutBehaviour="
            + this.logoutBehaviour
            + ", request="
            + this.request
            + ", response="
            + this.response
            + ", tokenRepository="
            + this.tokenRepository
            + ", principalInfo="
            + this.principalInfo
            + ", signingLogger="
            + this.signingLogger
            + ", helpdeskLogger="
            + this.helpdeskLogger
            + ")";
      }
   }
}
