/* global wp, jQuery, React, ReactDOM, _ */
import KirkiSelectForm from "./KirkiSelectForm";

const wpReactRender = ( target, reactNode ) => {
	if ( target ) {

    if ( wp.element.createRoot ) {
			wp.element.createRoot( target ).render( wp.element.reactNode );
    } else {
			wp.element.render( reactNode, target );
    }
	}
};

/**
 * KirkiSelectControl.
 *
 * @class
 * @augments wp.customize.Control
 * @augments wp.customize.Class
 */
const KirkiSelectControl = wp.customize.Control.extend({
  /**
   * Initialize.
   *
   * @param {string} id - Control ID.
   * @param {object} params - Control params.
   */
  initialize: function (id, params) {
    const control = this;

    // Bind functions to this control context for passing as React props.
    control.setNotificationContainer =
      control.setNotificationContainer.bind(control);

    wp.customize.Control.prototype.initialize.call(control, id, params);

    // The following should be eliminated with <https://core.trac.wordpress.org/ticket/31334>.
    function onRemoved(removedControl) {
      if (control === removedControl) {
        control.destroy();
        control.container.remove();
        wp.customize.control.unbind("removed", onRemoved);
      }
    }
    wp.customize.control.bind("removed", onRemoved);
  },

  /**
   * Set notification container and render.
   *
   * This is called when the React component is mounted.
   *
   * @param {Element} element - Notification container.
   * @returns {void}
   */
  setNotificationContainer: function setNotificationContainer(element) {
    const control = this;
    control.notifications.container = jQuery(element);
    control.notifications.render();
  },

  /**
   * Render the control into the DOM.
   *
   * This is called from the Control#embed() method in the parent class.
   *
   * @returns {void}
   */
  renderContent: function renderContent() {
    const control = this;
    let value = control.setting.get();

    if (Array.isArray(value)) {
      let formattedValue = [];

      for (const key in control.params.choices) {
        if (control.params.choices.hasOwnProperty(key)) {
          if (value.includes(key)) {
            // formattedValue.push();
          }
        }
      }

      // value = control.params.choices;
    }

    const form = (
      <KirkiSelectForm
        {...control.params}
        value={value}
        setNotificationContainer={control.setNotificationContainer}
        isClearable={control.params.isClearable}
        customizerSetting={control.setting}
        isOptionDisabled={control.isOptionDisabled}
        control={control}
        isMulti={control.isMulti()}
        maxSelectionNumber={control.params.maxSelectionNumber}
      />
    );
    wpReactRender(control.container[0], form);
  },

  /**
   * After control has been first rendered, start re-rendering when setting changes.
   *
   * React is able to be used here instead of the wp.customize.Element abstraction.
   *
   * @returns {void}
   */
  ready: function ready() {
    const control = this;

    // Re-render control when setting changes.
    control.setting.bind(() => {
      control.renderContent();
    });
  },

  isMulti: function () {
    return this.params.isMulti;
  },

  /**
   * Handle removal/de-registration of the control.
   *
   * This is essentially the inverse of the Control#embed() method.
   *
   * @link https://core.trac.wordpress.org/ticket/31334
   * @returns {void}
   */
  destroy: function destroy() {
    const control = this;

    // Garbage collection: undo mounting that was done in the embed/renderContent method.
    ReactDOM.unmountComponentAtNode(control.container[0]);

    // Call destroy method in parent if it exists (as of #31334).
    if (wp.customize.Control.prototype.destroy) {
      wp.customize.Control.prototype.destroy.call(control);
    }
  },

  isOptionDisabled: function (option) {
    const control = this;

    if (!control) return false;
    if (!control.disabledSelectOptions) return false;
    if (control.disabledSelectOptions.indexOf(option)) return true;

    return false;
  },

  doSelectAction: function (action, arg) {
    const control = this;
    let i;

    switch (action) {
      case "disableOption":
        control.disabledSelectOptions =
          "undefined" === typeof control.disabledSelectOptions
            ? []
            : control.disabledSelectOptions;
        control.disabledSelectOptions.push(control.getOptionProps(arg));
        break;

      case "enableOption":
        if (control.disabledSelectOptions) {
          for (i = 0; i < control.disabledSelectOptions.length; i++) {
            if (control.disabledSelectOptions[i].value === arg) {
              control.disabledSelectOptions.splice(i, 1);
            }
          }
        }
        break;

      case "selectOption":
        control.value = arg;
        break;
    }

    control.renderContent();
  },

  formatOptions: function () {
    var self = this;
    this.formattedOptions = [];

    if (Array.isArray(this.params.choices)) {
      this.formattedOptions = this.params.choices;
      return;
    }

    _.each(self.params.choices, function (label, value) {
      var optGroup;

      if ("object" === typeof label) {
        optGroup = {
          label: label[0],
          options: [],
        };

        _.each(label[1], function (optionVal, optionKey) {
          optGroup.options.push({
            label: optionVal,
            value: optionKey,
          });
        });

        self.formattedOptions.push(optGroup);
      } else if ("string" === typeof label) {
        self.formattedOptions.push({
          label: label,
          value: value,
        });
      }
    });
  },

  getFormattedOptions: function () {
    if (!this.formattedOptions || !this.formattedOptions.length) {
      this.formatOptions();
    }
    return this.formattedOptions;
  },

  getOptionProps: function (value) {
    const control = this;

    var options = this.getFormattedOptions(),
      i,
      l;

    if (control.isMulti()) {
      let values = [];

      for (i = 0; i < options.length; i++) {
        if (Array.isArray(value)) {
          const valueArray = value;

          valueArray.forEach(function (val) {
            if (options[i].value === val) {
              values.push(options[i]);
              return;
            }

            if (options[i].options) {
              for (l = 0; l < options[i].options.length; l++) {
                if (options[i].options[l].value === val) {
                  values.push(options[i].options[l]);
                }
              }
            }
          });
        } else {
          if (options[i].value === value) {
            values.push(options[i]);
          }

          if (options[i].options) {
            for (l = 0; l < options[i].options.length; l++) {
              if (options[i].options[l].value === value) {
                values.push(options[i].options[l]);
              }
            }
          }
        }
      }

      return values;
    } else {
      for (i = 0; i < options.length; i++) {
        if (options[i].value === value) {
          return options[i];
        }

        if (options[i].options) {
          for (l = 0; l < options[i].options.length; l++) {
            if (options[i].options[l].value === value) {
              return options[i].options[l];
            }
          }
        }
      }
    }
  },
});

export default KirkiSelectControl;
