/**
 * Rocketship UI JS: Forms.
 */

(function (Drupal, once, window, document) {
  "use strict";

  // Set namespace for frontend UI javascript.
  if (typeof window.rocketshipUI === 'undefined') {
    window.rocketshipUI = {};
  }

  const self = window.rocketshipUI;

  ///////////////////////////////////////////////////////////////////////
  // Behavior for Forms: triggers
  ///////////////////////////////////////////////////////////////////////

  Drupal.behaviors.rocketshipUIForms = {
    attach: (context) => {
      // Select input, select and textarea elements within the context.
      const inputs = context.querySelectorAll('input');
      const selects = context.querySelectorAll('select');
      const textareas = context.querySelectorAll('textarea');

      // Handle focus on form elements.
      if (inputs.length || textareas.length) {
        self.focusFields(inputs, textareas, selects);
      }

      // Wrap select tag to add custom styling and arrow.
      if (selects.length) {
        self.customSelect(selects);
      }

      // Detect text scroll in textarea so we can hide floating label.
      if (textareas.length) {
        self.textareaScroll(textareas);
      }

      // Check form states.
      self.stateCheck();
    }
  };

  ///////////////////////////////////////////////////////////////////////
  // Behavior for Forms: functions
  ///////////////////////////////////////////////////////////////////////

  /**
   * Add focus styles to form elements.
   *
   * @param {NodeListOf<HTMLInputElement>} inputs
   * A NodeListOf containing input elements.
   * @param {NodeListOf<HTMLTextAreaElement>} textareas
   * A NodeListOf containing textarea elements.
   * @param {NodeListOf<HTMLSelectElement>} selects
   * A NodeListOf containing select elements.
   */
  self.focusFields = (inputs, textareas, selects) => {
    // If input exists.
    if (inputs.length) {
      // Iterate all inputs.
      inputs.forEach((inputElement)=> {
        if (!inputElement.classList.contains('input-processed')) {
          inputElement.classList.add('input-processed');
          var input = inputElement;
          var wrapper = '.form__element';

          if (!input.closest(wrapper)) {
            wrapper = '.form-wrapper';
          }

          // Add an active class on wrapper and label if focus
          input.addEventListener('focus', () => {
            var closestWrapper = input.closest(wrapper);
            if (closestWrapper) {
              closestWrapper.classList.add('is-active');
              const label = closestWrapper.querySelector('label');
              if (label) {
                label.classList.add('is-active');
              }
            }

            // Some forms don't have wrappers with a class,
            // just use parent instead
            if (input.getAttribute('name') === 'search_block_form') {
              input.parentNode.classList.add('is-active');
              const label = input.parentNode.querySelector('label');
              if (label) {
                label.classList.add('is-active');
              }
            }
          });

          // Remove active class on blur
          input.addEventListener('blur', () => {
            const closestWrapper = input.closest(wrapper);
            if (closestWrapper) {
              closestWrapper.classList.remove('is-active');
              const label = closestWrapper.querySelector('label');
              if (label) {
                label.classList.remove('is-active');
              }
            }

            if (input.getAttribute('name') === 'search_block_form') {
              input.parentNode.classList.remove('is-active');
              const label = input.parentNode.querySelector('label');
              if (label) {
                label.classList.remove('is-active');
              }
            }

            // If field has a value, add a has-value class (handy for floating labels)
            if (input.value) {
              if (closestWrapper) {
                closestWrapper.classList.add('has-value');
                const label = closestWrapper.querySelector('label');
                if (label) {
                  label.classList.add('has-value');
                }
              }
              if (input.getAttribute('name') === 'search_block_form') {
                input.parentNode.classList.add('has-value');
                const label = input.parentNode.querySelector('label');
                if (label) {
                  label.classList.add('has-value');
                }
              }
              // Remove value class if empty
            } else {
              if (closestWrapper) {
                closestWrapper.classList.remove('has-value');
                const label = closestWrapper.querySelector('label');
                if (label) {
                  label.classList.remove('has-value');
                }
              }
              if (input.getAttribute('name') === 'search_block_form') {
                input.parentNode.classList.remove('has-value');
                const label = input.parentNode.querySelector('label');
                if (label) {
                  label.classList.remove('has-value');
                }
              }
            }
          });

          // If field has a value, add a has-value class (handy for floating labels)
          if (input.value) {
            var closestWrapper = input.closest(wrapper);
            if (closestWrapper) {
              closestWrapper.classList.add('has-value');
              const label = closestWrapper.querySelector('label');
              if (label) {
                label.classList.add('has-value');
              }
            }
            if (input.getAttribute('name') === 'search_block_form') {
              input.parentNode.classList.add('has-value');
              const label = input.parentNode.querySelector('label');
              if (label) {
                label.classList.add('has-value');
              }
            }
          }
        }
      });
    }

    if (textareas.length) {
      textareas.forEach((textareaElement) => {
        if (!textareaElement.classList.contains('textarea-processed')) {
          textareaElement.classList.add('textarea-processed');
          var textarea = textareaElement;
          var wrapper = '.form__element';

          if (!textarea.closest(wrapper)) {
            wrapper = '.form-wrapper';
          }

          // Add an active class on wrapper and label if focus
          textarea.addEventListener('focus',  () => {
            var closestWrapper = textarea.closest(wrapper);
            if (closestWrapper) {
              closestWrapper.classList.add('is-active');
              const label = closestWrapper.querySelector('label');
              if (label) {
                label.classList.add('is-active');
              }
            }
          });

          // Remove active class on blur
          textarea.addEventListener('blur',  () => {
            var closestWrapper = textarea.closest(wrapper);
            if (closestWrapper) {
              closestWrapper.classList.remove('is-active');
              const label = closestWrapper.querySelector('label');
              if (label) {
                label.classList.remove('is-active');
              }
            }

            // If textarea has a value, add a has-value class (handy for floating labels).
            if (textarea.value) {
              if (closestWrapper) {
                closestWrapper.classList.add('has-value');
                const label = closestWrapper.querySelector('label');
                if (label) {
                  label.classList.add('has-value');
                }
              }
              // Remove value class if empty.
            } else {
              if (closestWrapper) {
                closestWrapper.classList.remove('has-value');
                const label = closestWrapper.querySelector('label');
                if (label) {
                  label.classList.remove('has-value');
                }
              }
            }
          });

          // If field has a value, add a has-value class (handy for floating labels).
          if (textarea.value) {
            var closestWrapper = textarea.closest(wrapper);
            if (closestWrapper) {
              closestWrapper.classList.add('has-value');
              const label = closestWrapper.querySelector('label');
              if (label) {
                label.classList.add('has-value');
              }
            }
          }
        }
      });
    }

    if (selects.length) {
      once('select', selects).forEach((selectElement) => {
        selectElement.classList.add('select-processed');
        var select = selectElement;
        var wrapper = '.form__element';

        if (!select.closest(wrapper)) {
          wrapper = '.form-wrapper';
        }

        select.addEventListener('focus', () => {
          var parentElement = select.parentNode.parentNode;
          const label = parentElement.querySelector('label');
          if (label) {
            label.classList.add('is-active');
          }
        });

        select.addEventListener('blur', () => {
          const closestWrapper = select.closest(wrapper);
          if (closestWrapper) {
            closestWrapper.classList.remove('is-active');
            const label = closestWrapper.querySelector('label');
            if (label) {
              label.classList.remove('is-active');
            }

            if (select.value) {
              closestWrapper.classList.add('has-value');
              if (label) {
                label.classList.add('has-value');
              }
            } else {
              closestWrapper.classList.remove('has-value');
              if (label) {
                label.classList.remove('has-value');
              }
            }
          }
        });

        if (select.value) {
          const closestWrapper = select.closest(wrapper);
          // If value is not a string but data of some sort, check for it to be filled
          if (typeof select.value === 'object' && select.value.length > 0) {
            if (closestWrapper) {
              closestWrapper.classList.add('has-value');
              const label = closestWrapper.querySelector('label');
              if (label) {
                label.classList.add('has-value');
              }
            }
          }

          // If value as a string
          if (typeof select.value !== 'object') {
            if (closestWrapper) {
              closestWrapper.classList.add('has-value');
              var label = closestWrapper.querySelector('label');
              if (label) {
                label.classList.add('has-value');
              }
            }
          }
        }
      });
    }
  };

  /**
   * Wrap select in order to create custom styling for arrow and such.
   *
   * @param {NodeListOf<HTMLSelectElement>} selects
   * A NodeListOf containing select elements.
   */
  self.customSelect = (selects) => {
    once('select-wrap', selects).forEach((selectElement) => {
      if (!selectElement.closest('.form__dropdown')) {
        var wrapper = document.createElement('div');
        wrapper.className = 'form__dropdown';
        selectElement.parentNode.insertBefore(wrapper, selectElement);
        wrapper.appendChild(selectElement);
      }
    });
  };

  /**
   * Detect text scroll in textarea so we can hide floating label.
   *
   * When text top is not 0, hide the floating label (set a class on field).
   *
   * @param {NodeListOf<HTMLTextAreaElement>} textareas
   * A NodeListOf containing textarea elements.
   */
  self.textareaScroll = (textareas) => {
    once('textarea-scroll', textareas).forEach((textareaElement) => {
      var myTextarea = textareaElement;

      var checkScrollPosition = (self) => {
        // If text scrolls by, set a class on field
        // Could be used to hide the label or do something else.
        if (self.scrollTop > 0) {
          myTextarea.closest('.form__element').classList.add('js-scrolling');
        } else {
          myTextarea.closest('.form__element').classList.remove('js-scrolling');
        }
      };

      checkScrollPosition(myTextarea);

      myTextarea.addEventListener('scroll', () => {
        checkScrollPosition(this);
      });
    });
  };

  /**
   * Make our optional functionality work with states.
   */
  self.stateCheck = () => {
    document.addEventListener('state:required', (e) => {
      if (e.detail.trigger && typeof e.target.isWebform === 'function' && e.target.isWebform()) {
        var target = e.target;
        var label = target.parentNode.querySelector('.form__label');
        var requiredEl = label ? label.querySelector('.form__label__required') : null;
        var optionalEl = label ? label.querySelector('.form__label__not-required') : null;

        if (e.detail.value) {
          // Hide the 'optional' element via aria & show the 'required' one.
          if (requiredEl) {
            requiredEl.removeAttribute('aria-hidden');
          }
          if (optionalEl) {
            optionalEl.setAttribute('aria-hidden', 'true');
          }
        } else {
          // Hide the 'required' element via aria & show the 'optional' one.
          if (optionalEl) {
            optionalEl.removeAttribute('aria-hidden');
          }
          if (requiredEl) {
            requiredEl.setAttribute('aria-hidden', 'true');
          }
        }
      }
    });
  };
})(Drupal, once, window, document);
