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

import com.airlock.iam.authentication.api.domain.service.username.IdentificationResult;
import com.airlock.iam.authentication.api.domain.service.username.IdentityProvidingService;
import com.airlock.iam.authentication.domain.model.rememberme.RememberMeJspSecret;
import com.airlock.iam.authentication.domain.model.rememberme.RememberMeJspToken;
import com.airlock.iam.authentication.domain.model.rememberme.RememberMeJspTokenHmacKey;
import com.airlock.iam.authentication.domain.model.rememberme.RememberMeJspTokenHmacKeyId;
import com.airlock.iam.base.api.domain.model.user.UserId;
import com.airlock.iam.base.misc.result.Result;
import com.airlock.iam.common.api.domain.model.user.ProvidedUsername;
import com.airlock.iam.flow.shared.domain.model.rememberme.RememberMeSecret;
import com.airlock.iam.flow.shared.domain.model.rememberme.RememberMeToken;
import com.airlock.iam.flow.shared.domain.model.rememberme.RememberMeTokenLifetime;
import com.airlock.iam.flow.shared.domain.model.rememberme.RememberMeTokenRepository;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.util.Optional;

public final class RememberMeTokenVerificationServiceImpl implements RememberMeTokenVerificationService {
   private final Provider<RememberMeTokenRepository> repository;
   private final Provider<RememberMeTokenLifetime> tokenLifetime;
   private final Provider<IdentityProvidingService> identityService;
   private final Optional<RememberMeJspUserSecretPersisterService> jspPersisterService;
   private final Optional<RememberMeTokenLifetime> jspTokenLifetime;

   @Inject
   private RememberMeTokenVerificationServiceImpl(
      Provider<RememberMeTokenRepository> repository,
      Provider<RememberMeTokenLifetime> tokenLifetime,
      Provider<IdentityProvidingService> identityService,
      Optional<RememberMeJspUserSecretPersisterService> jspPersisterService,
      Optional<RememberMeTokenLifetime> jspTokenLifetime
   ) {
      this.repository = repository;
      this.tokenLifetime = tokenLifetime;
      this.identityService = identityService;
      this.jspPersisterService = jspPersisterService;
      this.jspTokenLifetime = jspTokenLifetime;
   }

   @Override
   public Result<RememberMeToken, RememberMeTokenVerificationService.RememberMeVerificationFailure> verifyToken(RememberMeSecret secret) {
      Optional<RememberMeToken> token = ((RememberMeTokenRepository)this.repository.get()).findBy(secret.hash());
      if (token.isEmpty()) {
         return Result.failure(RememberMeTokenVerificationService.RememberMeVerificationFailure.REMEMBER_ME_TOKEN_NOT_FOUND);
      } else {
         return token.get().isExpired((RememberMeTokenLifetime)this.tokenLifetime.get())
            ? Result.failure(RememberMeTokenVerificationService.RememberMeVerificationFailure.REMEMBER_ME_TOKEN_EXPIRED)
            : Result.result(token.get());
      }
   }

   @Override
   public IdentificationResult identifyTokenOwner(UserId tokenUserId) {
      return ((IdentityProvidingService)this.identityService.get()).tryIdentify(ProvidedUsername.providedUsernameOf(tokenUserId.getValue()));
   }

   @Override
   public Optional<RememberMeJspToken> verifyJspToken(RememberMeJspSecret secret) {
      Optional<RememberMeJspTokenHmacKeyId> keyId = RememberMeJspTokenValidator.extractHmacKeyId(secret);
      if (keyId.isPresent()) {
         Optional<RememberMeJspTokenHmacKey> userSecret = this.jspPersisterService.orElseThrow().findBy(keyId.get());
         if (userSecret.isPresent()) {
            return RememberMeJspTokenValidator.validateToken(secret, keyId.get(), userSecret.get(), this.jspTokenLifetime.orElseThrow());
         }
      }

      return Optional.empty();
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public static class RememberMeTokenVerificationServiceImplBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private Provider<RememberMeTokenRepository> repository;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<RememberMeTokenLifetime> tokenLifetime;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<IdentityProvidingService> identityService;
      @SuppressFBWarnings(justification = "generated code")
      private Optional<RememberMeJspUserSecretPersisterService> jspPersisterService;
      @SuppressFBWarnings(justification = "generated code")
      private Optional<RememberMeTokenLifetime> jspTokenLifetime;

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

      @SuppressFBWarnings(justification = "generated code")
      public RememberMeTokenVerificationServiceImpl.RememberMeTokenVerificationServiceImplBuilder repository(Provider<RememberMeTokenRepository> repository) {
         this.repository = repository;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public RememberMeTokenVerificationServiceImpl.RememberMeTokenVerificationServiceImplBuilder tokenLifetime(Provider<RememberMeTokenLifetime> tokenLifetime) {
         this.tokenLifetime = tokenLifetime;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public RememberMeTokenVerificationServiceImpl.RememberMeTokenVerificationServiceImplBuilder identityService(
         Provider<IdentityProvidingService> identityService
      ) {
         this.identityService = identityService;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public RememberMeTokenVerificationServiceImpl.RememberMeTokenVerificationServiceImplBuilder jspPersisterService(
         Optional<RememberMeJspUserSecretPersisterService> jspPersisterService
      ) {
         this.jspPersisterService = jspPersisterService;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public RememberMeTokenVerificationServiceImpl.RememberMeTokenVerificationServiceImplBuilder jspTokenLifetime(
         Optional<RememberMeTokenLifetime> jspTokenLifetime
      ) {
         this.jspTokenLifetime = jspTokenLifetime;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public RememberMeTokenVerificationServiceImpl build() {
         return new RememberMeTokenVerificationServiceImpl(
            this.repository, this.tokenLifetime, this.identityService, this.jspPersisterService, this.jspTokenLifetime
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "RememberMeTokenVerificationServiceImpl.RememberMeTokenVerificationServiceImplBuilder(repository="
            + this.repository
            + ", tokenLifetime="
            + this.tokenLifetime
            + ", identityService="
            + this.identityService
            + ", jspPersisterService="
            + this.jspPersisterService
            + ", jspTokenLifetime="
            + this.jspTokenLifetime
            + ")";
      }
   }
}
