package com.airlock.iam.apipolicyservice.infrastructure.credential;

import com.airlock.iam.apipolicyservice.application.configuration.ApiPolicyServiceAppConfig;
import com.airlock.iam.base.misc.time.RealTimeProvider;
import com.airlock.iam.base.misc.time.TimeProvider;
import com.airlock.iam.common.api.domain.model.authentication.AuthenticationResult;
import com.airlock.iam.common.api.domain.model.credential.RequestAuthentication;
import com.airlock.iam.common.api.domain.model.request.Request;
import com.airlock.iam.common.api.domain.model.user.transformation.UsernameTransformation;
import com.airlock.iam.common.domain.model.jwt.signature.JwsAlgorithmHmac;
import com.airlock.iam.common.domain.model.sso.SsoTicketExtractor;
import com.airlock.iam.common.domain.model.sso.SsoTicketRequestAuthentication;
import com.airlock.iam.common.domain.model.sso.SsoTicketStepSettings;
import com.airlock.iam.common.domain.service.jwt.JwtTicketDecoderImpl;
import com.airlock.iam.common.domain.service.jwt.signature.JwtSignatureVerifier;
import com.airlock.iam.common.domain.service.jwt.signature.JwtSignatureVerifierImpl;
import com.airlock.iam.common.domain.service.sso.SsoTicketServiceImpl;
import com.airlock.iam.common.domain.service.username.AcceptAllUsernameValidationService;
import jakarta.inject.Inject;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

public final class ApiPolicyServiceRequestAuthentication implements RequestAuthentication {
   public static final String API_POLICY_SERVICE_AUTH_HEADER = "X-AL-ApiPolicy-Auth";
   public static final String API_POLICY_SERVICE_JWT_USERNAME_CLAIM = "waf";
   private static final int API_POLICY_SERVICE_JWT_NBF_SKEW = 300;
   private final ApiPolicyServiceAppConfig config;

   @Inject
   public ApiPolicyServiceRequestAuthentication(ApiPolicyServiceAppConfig config) {
      this.config = config;
   }

   private SsoTicketRequestAuthentication createHeaderTicketRequestAuthentication(ApiPolicyServiceAppConfig config, Request request) {
      SsoTicketExtractor ticketExtractor = () -> request.extractHeaderValue("X-AL-ApiPolicy-Auth");
      return new SsoTicketRequestAuthentication(
         () -> ticketExtractor,
         UsernameTransformation::identity,
         () -> createSsoTicketService(config, ticketExtractor),
         AcceptAllUsernameValidationService::new
      );
   }

   public Optional<AuthenticationResult> extractCredentialAndAuthenticate(Request request) {
      return this.createHeaderTicketRequestAuthentication(this.config, request).extractCredentialAndAuthenticate(request);
   }

   private static SsoTicketServiceImpl createSsoTicketService(ApiPolicyServiceAppConfig config, SsoTicketExtractor ticketExtractor) {
      return SsoTicketServiceImpl.builder()
         .ticketDecoder(getJWTTicketDecoder(config.getSharedSecret()))
         .settings(new SsoTicketStepSettings("waf", Optional.empty(), false, false, Optional.empty(), false))
         .contextDataExtractors(Collections.emptyList())
         .acceptedSsoTicketService(Optional.empty())
         .ticketExtractors(List.of(ticketExtractor))
         .roleExtractors(Collections.emptyList())
         .build();
   }

   private static JwtTicketDecoderImpl getJWTTicketDecoder(String hmacKey) {
      return JwtTicketDecoderImpl.builder(createHmacJWTSignatureVerifier(hmacKey), createTimeProvider()).validNotBeforeSkew(300).build();
   }

   private static TimeProvider createTimeProvider() {
      return new RealTimeProvider();
   }

   private static JwtSignatureVerifier createHmacJWTSignatureVerifier(String hmacKey) {
      return new JwtSignatureVerifierImpl(JwsAlgorithmHmac.HS512, hmacKey);
   }
}
