package com.airlock.iam.common.infrastructure.factory;

import com.airlock.iam.base.api.infrastructure.plugin.PluginConfigToLogic;
import com.airlock.iam.common.application.configuration.gateway.AirlockMicrogatewayConfig;
import com.airlock.iam.common.application.service.request.HttpHeaderRequestInformationServiceImpl;
import com.airlock.iam.common.domain.model.gateway.HttpRequestClientIpExtractor;
import com.airlock.iam.common.domain.model.gateway.HttpRequestIdExtractor;
import com.airlock.iam.common.domain.model.gateway.HttpRequestMtlsClientCertificateExtractor;
import com.airlock.iam.common.domain.model.gateway.HttpRequestUrlExtractor;
import com.airlock.iam.common.domain.model.request.ClientIp;
import com.airlock.iam.common.domain.model.request.ClientTlsCertificate;
import com.airlock.iam.common.domain.model.request.CorrelationId;
import com.airlock.iam.common.domain.model.request.RequestId;
import com.airlock.iam.common.domain.service.request.AirlockEnvCookiesInformationService;
import com.airlock.iam.common.domain.service.request.HttpHeaderRequestInformationService;
import com.airlock.iam.common.domain.service.request.HttpRequestInformationService;
import com.airlock.iam.common.domain.service.request.HttpServletRequestInformationService;
import com.airlock.iam.common.domain.service.session.CorrelationIdService;
import com.airlock.iam.common.infrastructure.request.AirlockEnvCookiesInformationServiceImpl;
import com.airlock.iam.common.infrastructure.request.HttpServletRequestInformationServiceImpl;
import com.airlock.iam.common.infrastructure.session.CorrelationIdServiceImpl;
import com.airlock.iam.core.application.configuration.waf.AirlockGatewayConfig;
import com.google.inject.Exposed;
import com.google.inject.PrivateModule;
import com.google.inject.Provides;
import com.google.inject.servlet.RequestScoped;
import jakarta.inject.Provider;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Optional;

public final class HttpRequestInformationModule extends PrivateModule {
   @Provides
   Optional<HttpRequestClientIpExtractor> provideClientIpExtractor(Optional<AirlockMicrogatewayConfig> mgwConfig, PluginConfigToLogic toLogic) {
      return mgwConfig.map(AirlockMicrogatewayConfig::getClientIpExtractor).map(toLogic::getLogic);
   }

   @Provides
   Optional<HttpRequestIdExtractor> provideRequestIdExtractor(Optional<AirlockMicrogatewayConfig> mgwConfig, PluginConfigToLogic toLogic) {
      return mgwConfig.map(AirlockMicrogatewayConfig::getRequestIdExtractor).map(toLogic::getLogic);
   }

   @Provides
   Optional<HttpRequestUrlExtractor> provideRequestUrlExtractor(Optional<AirlockMicrogatewayConfig> mgwConfig, PluginConfigToLogic toLogic) {
      return mgwConfig.map(AirlockMicrogatewayConfig::getRequestUrlExtractor).map(toLogic::getLogic);
   }

   @Provides
   Optional<HttpRequestMtlsClientCertificateExtractor> provideRequestMtlsClientCertExtractor(
      Optional<AirlockMicrogatewayConfig> mgwConfig, PluginConfigToLogic toLogic
   ) {
      return mgwConfig.map(AirlockMicrogatewayConfig::getRequestMtlsClientCertificateExtractor).map(toLogic::getLogic);
   }

   @Provides
   @RequestScoped
   @Exposed
   RequestId provideRequestId(CorrelationIdService correlationIdService) {
      return correlationIdService.determineRequestId();
   }

   @Provides
   @RequestScoped
   @Exposed
   CorrelationId provideCorrelationId(CorrelationIdService correlationIdService) {
      return correlationIdService.determineCorrelationId();
   }

   @Provides
   @RequestScoped
   @Exposed
   Optional<ClientTlsCertificate> provideMtlsClientCertificate(HttpRequestInformationService httpRequestInformationService) {
      return httpRequestInformationService.getMtlsClientCertificate();
   }

   @Provides
   @RequestScoped
   @Exposed
   ClientIp provideClientIp(HttpRequestInformationService httpRequestInformationService, HttpServletRequest request) {
      return httpRequestInformationService.getClientIp().orElseGet(() -> new ClientIp(request.getRemoteAddr()));
   }

   @Provides
   @RequestScoped
   @Exposed
   HttpRequestInformationService provideService(
      Optional<AirlockGatewayConfig> airlockConfig,
      Optional<AirlockMicrogatewayConfig> mgwConfig,
      Provider<HttpHeaderRequestInformationService> headerService,
      Provider<AirlockEnvCookiesInformationService> cookieService,
      Provider<HttpServletRequestInformationService> servletService
   ) {
      if (mgwConfig.isPresent()) {
         return (HttpRequestInformationService)headerService.get();
      } else {
         return airlockConfig.isPresent() ? (HttpRequestInformationService)cookieService.get() : (HttpRequestInformationService)servletService.get();
      }
   }

   protected void configure() {
      this.bind(CorrelationIdService.class).to(CorrelationIdServiceImpl.class);
      this.bind(HttpHeaderRequestInformationService.class).to(HttpHeaderRequestInformationServiceImpl.class);
      this.bind(AirlockEnvCookiesInformationService.class).to(AirlockEnvCookiesInformationServiceImpl.class);
      this.bind(HttpServletRequestInformationService.class).to(HttpServletRequestInformationServiceImpl.class);
      this.expose(AirlockEnvCookiesInformationService.class);
      this.expose(HttpServletRequestInformationService.class);
   }
}
