/**
 * @file
 * Polyfill for HTML5 date input.
 */

(function (Modernizr, Drupal, once) {
  /**
   * Attach datepicker fallback on date elements.
   *
   * @type {Drupal~behavior}
   *
   * @prop {Drupal~behaviorAttach} attach
   *   Attaches the behavior. Adds a class that hides formatting instructions
   *   on date/time fields when the browser supports a native datepicker.
   */
  Drupal.behaviors.date = {
    attach(context, settings) {
      // If the browser does not support a native datepicker, add date
      // formatting instructions on date/time fields.
      if (Modernizr.inputtypes.date === false) {
        once('datepicker', '[data-drupal-field-elements="date-time"]').forEach(
          (dateTime) => {
            const dateInput = dateTime.querySelector('input[type="date"]');
            const timeInput = dateTime.querySelector('input[type="time"]');
            const help = Drupal.theme.dateTimeHelp({
              dateId: `${dateInput.id}--description`,
              dateDesc: dateInput.dataset.help,
              timeId: `${timeInput.id}--description`,
              timeDesc: timeInput.dataset.help,
            });

            [dateInput, timeInput].forEach((input) => {
              input.setAttribute(
                'aria-describedby',
                `${input.id}--description`,
              );
              // If the browser does not support date or time inputs, the input
              // is treated as the type "text". The type attribute should be
              // changed to reflect this.
              input.setAttribute('type', 'text');
            });

            Drupal.DatepickerPolyfill.attachDescription(dateTime, help);
          },
        );

        once('datepicker', '[data-drupal-field-elements="date"]').forEach(
          (date) => {
            const dateInput = date.querySelector('input[type="date"]');
            const help = Drupal.theme.dateHelp({
              dateDesc: dateInput.dataset.help,
            });

            // Date-only input will be described by description directly.
            const id = `${date.id}--description`;
            dateInput.setAttribute('aria-describedby', id);

            // If the browser does not support date inputs, the input is treated
            // as the type "text". The type attribute should be changed to
            // changed to reflect this.
            dateInput.setAttribute('type', 'text');
            Drupal.DatepickerPolyfill.attachDescription(date, help, id);
          },
        );
      }
    },
  };

  /**
   * Provides overridable utility functions for the datepicker polyfill.
   */
  Drupal.DatepickerPolyfill = class {
    /**
     * Adds help text to polyfilled date/time elements.
     *
     * The help text is added to existing description elements when present.
     * If a description element is not present, one is created.
     *
     * @param {HTMLElement} element
     *   The input element.
     * @param {string} help
     *   The help text.
     * @param {string} id
     *   The input id.
     */
    static attachDescription(element, help, id) {
      let description = element.nextElementSibling;

      // If no description element exists, create one.
      if (
        !(
          description &&
          description.getAttribute('data-drupal-field-elements') ===
            'description'
        )
      ) {
        description = Drupal.DatepickerPolyfill.descriptionWrapperElement(id);
        element.parentNode.insertBefore(description, element.nextSibling);
      }
      description.insertAdjacentHTML('beforeend', help);
    }

    /**
     * Creates a description wrapper element.
     *
     * @param {string} id
     *   The id of the input being described.
     *
     * @return {HTMLElement}
     *   The description wrapper DOM element.
     */
    static descriptionWrapperElement(id) {
      const description = document.createElement('div');
      description.classList.add('description');
      description.setAttribute('data-drupal-field-elements', 'description');
      if (id) {
        description.setAttribute('id', id);
      }
      return description;
    }
  };

  /**
   * Theme function for no-native-datepicker date input help text.
   *
   * @param {string} dateDesc
   *   The help text.
   *
   * @return {string}
   *   The HTML markup for the help text.
   */
  Drupal.theme.dateHelp = ({ dateDesc }) =>
    `<div class="no-native-datepicker-help">${dateDesc}</div>`;

  /**
   * Theme function for no-native-datepicker date+time inputs help text.
   *
   * @param {string} dateId
   *   The date input aria-describedby value.
   * @param {string} timeId
   *   The time input aria-describedby value.
   * @param {string} dateDesc
   *   The date help text.
   * @param {string} timeDesc
   *   The time help text.
   *
   * @return {string}
   *   The HTML markup for the help text.
   */
  Drupal.theme.dateTimeHelp = ({ dateId, timeId, dateDesc, timeDesc }) =>
    `<div class="no-native-datepicker-help">
       <span id="${dateId}">${dateDesc}</span> <span id="${timeId}">${timeDesc}</span>
     </div>`;
})(Modernizr, Drupal, once);
