package com.airlock.iam.login.domain.model.targetapp;

import com.airlock.iam.base.api.domain.model.plugin.LogicForConfig;
import com.airlock.iam.common.api.domain.model.role.Role;
import com.airlock.iam.common.domain.model.auth.idpropagation.WafCredential;
import com.airlock.iam.common.domain.model.auth.idpropagation.WafCredentialIdleTimeout;
import com.airlock.iam.common.domain.model.auth.idpropagation.WafCredentialLifetime;
import com.airlock.iam.common.domain.model.auth.idpropagation.WafCredentialTimeout;
import com.airlock.iam.common.domain.model.principal.UserPrincipal;
import com.airlock.iam.flow.shared.domain.model.valueprovider.RoleProvider;
import com.airlock.iam.login.application.configuration.targetapp.AirlockGatewayRolesConfig;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.time.Duration;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@LogicForConfig(AirlockGatewayRolesConfig.class)
public class GenericWafCredentialProvider implements WafCredentialProvider {
   private final Provider<UserPrincipal> principal;
   private final RoleProvider roleProvider;
   private final Optional<TimeoutProvider> timeoutProvider;

   @Inject
   public GenericWafCredentialProvider(Provider<UserPrincipal> principal, RoleProvider roleProvider, Optional<TimeoutProvider> timeoutProvider) {
      this.principal = principal;
      this.roleProvider = roleProvider;
      this.timeoutProvider = timeoutProvider;
   }

   @Override
   public List<WafCredential> getCredentials() {
      return ((UserPrincipal)this.principal.get()).getIdentity().isEmpty()
         ? List.of()
         : this.roleProvider
            .provideRoles(((UserPrincipal)this.principal.get()).getIdentity().get())
            .stream()
            .map(
               role -> this.timeoutProvider
                  .<WafCredential>map(provider -> getWafCredentialsFromTimeoutProvider(role, provider))
                  .orElse(getWafCredentialForRole(role))
            )
            .collect(Collectors.toList());
   }

   private static WafCredential getWafCredentialsFromTimeoutProvider(Role role, TimeoutProvider timeoutProvider) {
      return new WafCredential(role.getRoleName(), timeoutProvider.getTimeout());
   }

   private static WafCredential getWafCredentialForRole(Role role) {
      return new WafCredential(
         role.getRoleName(),
         WafCredentialTimeout.wafCredentialTimeout(
            role.getIdleTimeout().map(Duration::ofSeconds).map(WafCredentialIdleTimeout::idleTimeout),
            role.getLifetime().map(Duration::ofSeconds).map(WafCredentialLifetime::lifetime)
         )
      );
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public static class GenericWafCredentialProviderBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private Provider<UserPrincipal> principal;
      @SuppressFBWarnings(justification = "generated code")
      private RoleProvider roleProvider;
      @SuppressFBWarnings(justification = "generated code")
      private Optional<TimeoutProvider> timeoutProvider;

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

      @SuppressFBWarnings(justification = "generated code")
      public GenericWafCredentialProvider.GenericWafCredentialProviderBuilder principal(Provider<UserPrincipal> principal) {
         this.principal = principal;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public GenericWafCredentialProvider.GenericWafCredentialProviderBuilder roleProvider(RoleProvider roleProvider) {
         this.roleProvider = roleProvider;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public GenericWafCredentialProvider.GenericWafCredentialProviderBuilder timeoutProvider(Optional<TimeoutProvider> timeoutProvider) {
         this.timeoutProvider = timeoutProvider;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public GenericWafCredentialProvider build() {
         return new GenericWafCredentialProvider(this.principal, this.roleProvider, this.timeoutProvider);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "GenericWafCredentialProvider.GenericWafCredentialProviderBuilder(principal="
            + this.principal
            + ", roleProvider="
            + this.roleProvider
            + ", timeoutProvider="
            + this.timeoutProvider
            + ")";
      }
   }
}
