package com.airlock.iam.saml2.infrastructure.request;

import com.airlock.iam.core.domain.model.http.HttpRequestMethod;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.annotation.Nullable;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Map.Entry;
import lombok.NonNull;

public final class RebuiltInitialSpInitiatedSloRequest extends HttpServletRequestWrapper {
   private final Map<String, String> parameters;
   private final Optional<HttpRequestMethod> httpMethod;
   private final Optional<String> requestUri;
   private final Optional<String> queryString;

   RebuiltInitialSpInitiatedSloRequest(
      @NonNull HttpServletRequest request,
      @Nullable HttpRequestMethod httpMethod,
      @Nullable String requestUri,
      @Nullable String queryString,
      Map<String, String> parameters
   ) {
      super(request);
      if (request == null) {
         throw new NullPointerException("request is marked non-null but is null");
      }

      this.httpMethod = Optional.ofNullable(httpMethod);
      this.requestUri = Optional.ofNullable(requestUri);
      this.queryString = Optional.ofNullable(queryString);
      this.parameters = Collections.unmodifiableMap(parameters);
   }

   public String getMethod() {
      return this.httpMethod.map(Enum::name).orElseGet(() -> super.getMethod());
   }

   public String getRequestURI() {
      return this.requestUri.orElseGet(() -> super.getRequestURI());
   }

   public String getQueryString() {
      return this.queryString.orElseGet(() -> super.getQueryString());
   }

   public String getParameter(String name) {
      return this.parameters.get(name);
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public static class RebuiltInitialSpInitiatedSloRequestBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private HttpServletRequest request;
      @SuppressFBWarnings(justification = "generated code")
      private HttpRequestMethod httpMethod;
      @SuppressFBWarnings(justification = "generated code")
      private String requestUri;
      @SuppressFBWarnings(justification = "generated code")
      private String queryString;
      @SuppressFBWarnings(justification = "generated code")
      private ArrayList<String> parameters$key;
      @SuppressFBWarnings(justification = "generated code")
      private ArrayList<String> parameters$value;

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

      @SuppressFBWarnings(justification = "generated code")
      public RebuiltInitialSpInitiatedSloRequest.RebuiltInitialSpInitiatedSloRequestBuilder request(@NonNull HttpServletRequest request) {
         if (request == null) {
            throw new NullPointerException("request is marked non-null but is null");
         }

         this.request = request;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public RebuiltInitialSpInitiatedSloRequest.RebuiltInitialSpInitiatedSloRequestBuilder httpMethod(@Nullable HttpRequestMethod httpMethod) {
         this.httpMethod = httpMethod;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public RebuiltInitialSpInitiatedSloRequest.RebuiltInitialSpInitiatedSloRequestBuilder requestUri(@Nullable String requestUri) {
         this.requestUri = requestUri;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public RebuiltInitialSpInitiatedSloRequest.RebuiltInitialSpInitiatedSloRequestBuilder queryString(@Nullable String queryString) {
         this.queryString = queryString;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public RebuiltInitialSpInitiatedSloRequest.RebuiltInitialSpInitiatedSloRequestBuilder parameter(String parameterKey, String parameterValue) {
         if (this.parameters$key == null) {
            this.parameters$key = new ArrayList<>();
            this.parameters$value = new ArrayList<>();
         }

         this.parameters$key.add(parameterKey);
         this.parameters$value.add(parameterValue);
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public RebuiltInitialSpInitiatedSloRequest.RebuiltInitialSpInitiatedSloRequestBuilder parameters(Map<? extends String, ? extends String> parameters) {
         if (parameters == null) {
            throw new NullPointerException("parameters cannot be null");
         }

         if (this.parameters$key == null) {
            this.parameters$key = new ArrayList<>();
            this.parameters$value = new ArrayList<>();
         }

         for (Entry<? extends String, ? extends String> $lombokEntry : parameters.entrySet()) {
            this.parameters$key.add($lombokEntry.getKey());
            this.parameters$value.add($lombokEntry.getValue());
         }

         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public RebuiltInitialSpInitiatedSloRequest.RebuiltInitialSpInitiatedSloRequestBuilder clearParameters() {
         if (this.parameters$key != null) {
            this.parameters$key.clear();
            this.parameters$value.clear();
         }

         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public RebuiltInitialSpInitiatedSloRequest build() {
         return new RebuiltInitialSpInitiatedSloRequest(
            this.request,
            this.httpMethod,
            this.requestUri,
            this.queryString,
            switch (this.parameters$key == null ? 0 : this.parameters$key.size()) {
               case 0 -> Collections.emptyMap();
               case 1 -> Collections.singletonMap(this.parameters$key.get(0), this.parameters$value.get(0));
               default -> {
                  Map<String, String> parameters = new LinkedHashMap<>(
                     this.parameters$key.size() < 1073741824 ? 1 + this.parameters$key.size() + (this.parameters$key.size() - 3) / 3 : Integer.MAX_VALUE
                  );

                  for (int $i = 0; $i < this.parameters$key.size(); $i++) {
                     parameters.put(this.parameters$key.get($i), this.parameters$value.get($i));
                  }

                  yield Collections.unmodifiableMap(parameters);
               }
            }
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "RebuiltInitialSpInitiatedSloRequest.RebuiltInitialSpInitiatedSloRequestBuilder(request="
            + this.request
            + ", httpMethod="
            + this.httpMethod
            + ", requestUri="
            + this.requestUri
            + ", queryString="
            + this.queryString
            + ", parameters$key="
            + this.parameters$key
            + ", parameters$value="
            + this.parameters$value
            + ")";
      }
   }
}
