module PageHelpers
  module ReactHelpers
    def self.included(base)
      base.extend ClassMethods
    end

    # form_element should contain both dropdown and placeholder elements
    # its class will usually be something like "Select Select--single is-searchable"
    def select_option_from_dropdown(form_element:, option_text:)
      # reporting filters need time to load data - during this time wait until is-disabled class is gone
      form_element.div_element(class: "is-disabled").wait_while(&:present?)

      form_element.span_element(class: "Select-arrow-zone").click

      # populate with result so we don't have to loop through so many options
      form_element.div_element(class: "Select-input").text_field_element.element.set option_text
      form_element.div_element(class: "Select-input").text_field_element.send_keys :enter

      # # make sure the form has one and only one dropdown
      # possible_dropdowns = form_element.div_elements(class: "SelectInput-select")
      # # possible_dropdowns = form_element.div_elements(class: "Select-menu")
      # # if possible dropdowns are 0, check to see if the dropdown is tethered
      # if possible_dropdowns.empty?
      #   tethered_list = div_element(class: "Select-menu-outer")
      #   possible_dropdowns = tethered_list.div_elements(class: "Select-menu")
      # end
      # dropdown = possible_dropdowns.assert_and_return_first_element
      #
      # # wait until dropdown populates
      # # wait_until(30) { dropdown.div_elements(class: "Select-option").count > 0 }
      # # wait_until(30) { dropdown.div_elements(class: "SelectInput-select").count > 0 }
      #
      # # make sure the dropdown has one and only one option
      # # possible_options = dropdown.div_elements(class: "Select-option", text: option_text)
      # # option = possible_options.assert_and_return_first_element
      #
      # option.click
    end

    def add_new_option_to_dropdown(form_element:, data:)
      possible_add_new_buttons = form_element.button_elements(class: "SelectInputWithAddNew-add-button")
      add_new_button = possible_add_new_buttons.assert_and_return_first_element
      add_new_button.click

      possible_add_new_boxes = form_element.article_elements(class: "SelectInputWithAddNew-new-box")
      add_new_box = possible_add_new_boxes.assert_and_return_first_element
      add_new_box.text_field_element(class: "FormField-form-control").append data

      add_new_button = add_new_box.button_element(text: /Add/)
      wait_until { add_new_button.element.enabled? }
      add_new_button.click

      wait_until { form_element.div(text: data).present? }
    end

    def react_drag_and_drop(point_a, point_b)
      # new solution using js drag and drop function with no jquery
      # https://gist.github.com/reinaldorossetti/074642e9f954b7119c557748836fcd42#file-drag-drop-js

      js_filepath = File.join(Support::Paths.plugins, "drag_and_drop_helper.js")
      js_file = File.new(js_filepath, "r")
      java_script = ""

      while (line = js_file.gets)
        java_script += line
      end

      js_file.close
      execute_script(java_script, point_a, point_b)
      # execute_script(java_script + "$('#{point_a}').simulateDragDrop({ dropTarget:'#{point_b}'});")
    rescue StandardError => e
      puts "ERROR :" + e.to_s
    end

    # rubocop:disable Custom/AvoidReflection
    module ClassMethods
      # accessor that creates methods for dropdowns with buttons to add new
      # options, such as imprint
      # TODO make this work like cheezy select list e.g. my_select = ""
      def react_select_or_create(name, identifier = { index: 0 }, &block)
        react_select(name, identifier, &block)

        define_method("create_#{name}") do |value|
          add_new_option_to_dropdown(
            form_element: send("#{name}_element"),
            data: value
          )
        end
      end

      # accessor that creates methods for dropdowns, such as meta language
      def react_select(name, identifier = { index: 0 }, &block)
        standard_methods(name, identifier, "div_for", &block)

        define_method(name) do
          send("#{name}_element").span_element(class: "Select-multi-value-wrapper").text
        end

        define_method("select_#{name}") do |value|
          select_option_from_dropdown(
            form_element: send("#{name}_element"),
            option_text: value
          )
        end
      end

      # accessor that creates methods for bubble inputs, such as primary artist
      def react_bubble_input(name, identifier = { index: 0 }, &block)
        standard_methods(name, identifier, "div_for", &block)
        define_method(name) do
          send("#{name}_element").span_elements(class: "TagsInput-tag").map(&:text)
        end

        define_method("#{name}=") do |value|
          text_input = send("#{name}_element").text_field_element.element
          # use \n to separate bubbles
          if value
            text_input.set value.join("\n")
            # patch to unfocus text field element
            send("#{name}_element").click
            # maybe switch back to this when chromedriver is fixed
            # text_input.set "\n"
          end
        end
      end

      # TODO: find a way to select options by things like ID instead. This may
      #   require the creation of a custom page object element instead.
      # accessor that creates methods for rows of buttons, such as pre-order
      def react_button_row(name, identifier = { index: 0 }, &block)
        standard_methods(name, identifier, "div_for", &block)

        define_method(name) do
          send("#{name}_element").button_element(class: "ButtonsRow-active").text
        end

        define_method("select_#{name}") do |value|
          element = send("#{name}_element")
          element.when_present
          element.button_element(text: value).click
        end
      end

      # TODO: - Probably needs to be removed, investigate. no refs to my knowledge.
      # accessor that creates methods for the quill rich text editor
      def react_rich_text_editor(name, identifier = { index: 0 }, &block)
        standard_methods(name, identifier, "div_for", &block)

        define_method(name) do
          send("#{name}_element").text
        end

        define_method("#{name}=") do |value|
          # wait to see if there is a value - loads async so give it a moment
          sleep 0.5
          # clear the field first
          number_of_chars = send(name).length

          # populate with new value
          input_watir_element = send("#{name}_element").element
          input_watir_element.send_keys Array.new(number_of_chars, :delete)
          input_watir_element.send_keys value
        end
      end
    end
    # rubocop:enable Custom/AvoidReflection
  end
end
