content: package org.allaymc.api.form.type;
  
  import com.google.gson.reflect.TypeToken;
  import lombok.Getter;
  import lombok.extern.slf4j.Slf4j;
  import org.allaymc.api.form.FormCancelReason;
  import org.allaymc.api.form.element.*;
  import org.jetbrains.annotations.ApiStatus;
  
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.List;
  import java.util.function.Consumer;
  
  /**
   * CustomForm is a type of form that can have a variety of elements and a submit button.
   * It is suitable when you want the viewer to fill and submit some information.
   *
   * @author daoge_cmd
   */
  @Getter
  @Slf4j
  public class CustomForm extends Form {
      @SuppressWarnings("unused")
      private final String type = "custom_form";
  
      private final List<CustomFormElement> content = new ArrayList<>();
      private String title = "";
      private ImageData icon;
      private transient Consumer<List<String>> onResponse = responses -> {
      };
  
      /**
       * Set the title of the form.
       *
       * @param title the title
       * @return the form
       */
      public CustomForm title(String title) {
          this.title = title;
          return this;
      }
  
      /**
       * Set the icon of the form.
       *
       * @param icon the icon
       * @return the form
       */
      public CustomForm icon(ImageData icon) {
          this.icon = icon;
          return this;
      }
  
      /**
       * Set the icon of the form.
       *
       * @param imageType the type of the image
       * @param data      the data of the image
       * @return the form
       */
      public CustomForm icon(ImageData.ImageType imageType, String data) {
          return icon(new ImageData(imageType, data));
      }
  
      /**
       * Set the icon of the form.
       *
       * @param path the path of the image
       * @return the form
       */
      public CustomForm pathIcon(String path) {
          return icon(new ImageData(ImageData.ImageType.PATH, path));
      }
  
      /**
       * Set the icon of the form.
       *
       * @param url the URL of the image
       * @return the form
       */
      public CustomForm urlIcon(String url) {
          return icon(new ImageData(ImageData.ImageType.URL, url));
      }
  
      /**
       * Add an element to the form.
       *
       * @param element the element
       * @return the form
       */
      public CustomForm element(CustomFormElement element) {
          content.add(element);
          return this;
      }
  
      /**
       * Add a dropdown element to the form.
       *
       * @param text the text of the element
       * @return the form
       */
      public CustomForm dropdown(String text) {
          return dropdown(text, new ArrayList<>());
      }
  
      /**
       * Add a dropdown element to the form.
       *
       * @param text    the text of the element
       * @param options the options of the element
       * @return the form
       */
      public CustomForm dropdown(String text, List<String> options) {
          return dropdown(text, options, 0);
      }
  
      /**
       * Add a dropdown element to the form.
       *
       * @param text    the text of the element
       * @param options the options of the element
       * @return the form
       */
      public CustomForm dropdown(String text, String... options) {
          return dropdown(text, new ArrayList<>(Arrays.asList(options)));
      }
  
      /**
       * Add a dropdown element to the form.
       *
       * @param text               the text of the element
       * @param options            the options of the element
       * @param defaultOptionIndex the index of the default option
       * @return the form
       */
      public CustomForm dropdown(String text, List<String> options, int defaultOptionIndex) {
          return element(new Dropdown(text, options, defaultOptionIndex));
      }
  
      /**
       * Add an input element to the form.
       *
       * @param text the text of the element
       * @return the form
       */
      public CustomForm input(String text) {
          return input(text, "");
      }
  
      /**
       * Add an input element to the form.
       *
       * @param text        the text of the element
       * @param placeholder the placeholder of the element
       * @return the form
       */
      public CustomForm input(String text, String placeholder) {
          return input(text, placeholder, "");
      }
  
      /**
       * Add an input element to the form.
       *
       * @param text        the text of the element
       * @param placeholder the placeholder of the element
       * @param defaultText the default text of the element
       * @return the form
       */
      public CustomForm input(String text, String placeholder, String defaultText) {
          return element(new Input(text, placeholder, defaultText));
      }
  
      /**
       * Add a label element to the form.
       *
       * @param text the text of the element
       * @return the form
       */
      public CustomForm label(String text) {
          return element(new Label(text));
      }
  
      /**
       * Add a slider element to the form.
       *
       * @param text the text of the element
       * @return the form
       */
      public CustomForm slider(String text, float min, float max) {
          return slider(text, min, max, 1);
      }
  
      /**
       * Add a slider element to the form.
       *
       * @param text the text of the element
       * @param min  the minimum value of the element
       * @param max  the maximum value of the element
       * @param step the step of the element
       * @return the form
       */
      public CustomForm slider(String text, float min, float max, int step) {
          return slider(text, min, max, step, min);
      }
  
      /**
       * Add a slider element to the form.
       *
       * @param text         the text of the element
       * @param min          the minimum value of the element
       * @param max          the maximum value of the element
       * @param step         the step of the element
       * @param defaultValue the default value of the element
       * @return the form
       */
      public CustomForm slider(String text, float min, float max, int step, float defaultValue) {
          return element(new Slider(text, min, max, step, defaultValue));
      }
  
      /**
       * Add a step slider element to the form.
       *
       * @param text the text of the element
       * @return the form
       */
      public CustomForm stepSlider(String text) {
          return stepSlider(text, new ArrayList<>());
      }
  
      /**
       * Add a step slider element to the form.
       *
       * @param text  the text of the element
       * @param steps the steps of the element
       * @return the form
       */
      public CustomForm stepSlider(String text, String... steps) {
          return stepSlider(text, new ArrayList<>(Arrays.asList(steps)));
      }
  
      /**
       * Add a step slider element to the form.
       *
       * @param text  the text of the element
       * @param steps the steps of the element
       * @return the form
       */
      public CustomForm stepSlider(String text, List<String> steps) {
          return stepSlider(text, steps, 0);
      }
  
      /**
       * Add a step slider element to the form.
       *
       * @param text        the text of the element
       * @param steps       the steps of the element
       * @param defaultStep the default step of the element
       * @return the form
       */
      public CustomForm stepSlider(String text, List<String> steps, int defaultStep) {
          return element(new StepSlider(text, steps, defaultStep));
      }
  
      /**
       * Add a toggle element to the form.
       *
       * @param text the text of the element
       * @return the form
       */
      public CustomForm toggle(String text) {
          return toggle(text, false);
      }
  
      /**
       * Add a toggle element to the form.
       *
       * @param text         the text of the element
       * @param defaultValue the default value of the element
       * @return the form
       */
      public CustomForm toggle(String text, boolean defaultValue) {
          return element(new Toggle(text, defaultValue));
      }
  
      /**
       * Add a header element to the form.
       *
       * @param text the text of the element
       * @return the form
       */
      public CustomForm header(String text) {
          return element(new Header(text));
      }
  
      /**
       * Add a divider element to the form.
       *
       * @return the form
       */
      public CustomForm divider() {
          return element(new Divider());
      }
  
      /**
       * Set the action to be performed when the form is submitted.
       *
       * @param onResponse the action to be performed when the form is submitted
       * @return the form
       */
      public CustomForm onResponse(Consumer<List<String>> onResponse) {
          this.onResponse = onResponse;
          return this;
      }
  
      /**
       * {@inheritDoc}
       */
      @Override
      public CustomForm onClose(Runnable onClose) {
          return (CustomForm) super.onClose(onClose);
      }
  
      /**
       * {@inheritDoc}
       */
      @Override
      public void handleResponse(String data) {
          List<String> responses = GSON.fromJson(data, new TypeToken<List<String>>() {
          }.getType());
          this.onResponse.accept(responses);
          this.response = responses;
      }
  
      /**
       * {@inheritDoc}
       */
      @Override
      public void handleClose(FormCancelReason reason) {
          onClose.accept(reason);
      }
  
      /**
       * This method is only used for server settings form.
       */
      @ApiStatus.Internal
      public void syncDefaultValueToResponse() {
          var response = getResponse();
          if (response == null) {
              log.warn("syncDefaultValueToResponse() called before receive response is called");
              return;
          }
          for (var index = 0; index < content.size(); index++) {
              var element = content.get(index);
              element.syncDefaultValueToResponse(response.get(index));
          }
      }
  
      /**
       * {@inheritDoc}
       */
      @Override
      public List<String> getResponse() {
          return response != null ? (List<String>) response : null;
      }
  }
  