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

import com.airlock.iam.common.domain.model.request.ClientIp;
import com.airlock.iam.common.domain.model.request.CorrelationId;
import com.airlock.iam.common.domain.model.request.RequestId;
import com.airlock.iam.common.domain.model.session.SessionId;
import com.airlock.iam.core.misc.util.IamLogUtil;
import com.airlock.iam.elog.api.ELogContext;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.plugin.api.config.ConfigurationContext;
import jakarta.annotation.Nonnull;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import jakarta.servlet.http.HttpServletRequest;

public final class LogContextInitializerImpl implements LogContextInitializer {
   public static final String ALREADY_INITIALIZED = "IAM_LOG_CONTEXT_ALREADY_INITIALIZED";
   private final Provider<HttpServletRequest> request;
   private final Provider<SessionId> sessionId;
   private final Provider<RequestId> requestId;
   private final Provider<ClientIp> clientIp;
   private final Provider<CorrelationId> correlationId;

   @Inject
   public LogContextInitializerImpl(
      @Nonnull Provider<HttpServletRequest> request,
      @Nonnull Provider<SessionId> sessionId,
      @Nonnull Provider<RequestId> requestId,
      @Nonnull Provider<ClientIp> clientIp,
      @Nonnull Provider<CorrelationId> correlationId
   ) {
      this.request = request;
      this.sessionId = sessionId;
      this.requestId = requestId;
      this.clientIp = clientIp;
      this.correlationId = correlationId;
   }

   @Override
   public void ensureInitialized() {
      if (!this.isAlreadyInitialized()) {
         this.markAsInitialized();
         ELogContext logContext = ELoggerFactory.getLogContext();
         IamLogUtil.initializeLogContext(logContext);
         logContext.put("GSID", ((SessionId)this.sessionId.get()).id());
         logContext.put("REQUEST_ID", ((RequestId)this.requestId.get()).id());
         if (((CorrelationId)this.correlationId.get()).isPresent()) {
            logContext.put("CORRELATION_ID", ((CorrelationId)this.correlationId.get()).id());
         } else {
            logContext.remove("CORRELATION_ID");
         }

         this.addClientIpToLogContext();
      }
   }

   private boolean isAlreadyInitialized() {
      Boolean already = (Boolean)((HttpServletRequest)this.request.get()).getAttribute("IAM_LOG_CONTEXT_ALREADY_INITIALIZED");
      return already != null && already;
   }

   private void markAsInitialized() {
      ((HttpServletRequest)this.request.get()).setAttribute("IAM_LOG_CONTEXT_ALREADY_INITIALIZED", Boolean.TRUE);
   }

   public static void updateConfigurationContext(ConfigurationContext configurationContext) {
      ELoggerFactory.getLogContext().put("CONFIG_CONTEXT", configurationContext.toString());
   }

   private void addClientIpToLogContext() {
      String clientIpValue = ((ClientIp)this.clientIp.get()).value();
      IamLogUtil.addRequestLogData((HttpServletRequest)this.request.get(), "clientIp", clientIpValue);
      ELoggerFactory.getLogContext().put("CLIENT_IP", clientIpValue);
   }
}
