import { HAS_PASSIVE_EVENT_SUPPORT } from '../constants/env';
import { ROOT_EVENT_NAME_PREFIX, ROOT_EVENT_NAME_SEPARATOR } from '../constants/events';
import { RX_BV_PREFIX } from '../constants/regex';
import { isObject } from './inspect';
import { kebabCase } from './string';

// --- Utils ---

// Normalize event options based on support of passive option
// Exported only for testing purposes
const parseEventOptions = options => {
  /* istanbul ignore else: can't test in JSDOM, as it supports passive */
  if (HAS_PASSIVE_EVENT_SUPPORT) {
    return isObject(options) ? options : {
      capture: !!options || false
    };
  } else {
    // Need to translate to actual Boolean value
    return !!(isObject(options) ? options.capture : options);
  }
};

// Attach an event listener to an element
const eventOn = (el, eventName, handler, options) => {
  if (el && el.addEventListener) {
    el.addEventListener(eventName, handler, parseEventOptions(options));
  }
};

// Remove an event listener from an element
const eventOff = (el, eventName, handler, options) => {
  if (el && el.removeEventListener) {
    el.removeEventListener(eventName, handler, parseEventOptions(options));
  }
};

// Utility method to add/remove a event listener based on first argument (boolean)
// It passes all other arguments to the `eventOn()` or `eventOff` method
const eventOnOff = function (on) {
  const method = on ? eventOn : eventOff;
  for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
    args[_key - 1] = arguments[_key];
  }
  method(...args);
};

// Utility method to prevent the default event handling and propagation
const stopEvent = function (event) {
  let {
    preventDefault = true,
    propagation = true,
    immediatePropagation = false
  } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  if (preventDefault) {
    event.preventDefault();
  }
  if (propagation) {
    event.stopPropagation();
  }
  if (immediatePropagation) {
    event.stopImmediatePropagation();
  }
};

// Helper method to convert a component/directive name to a base event name
// `getBaseEventName('BNavigationItem')` => 'navigation-item'
// `getBaseEventName('BVToggle')` => 'toggle'
const getBaseEventName = value => kebabCase(value.replace(RX_BV_PREFIX, ''));

// Get a root event name by component/directive and event name
// `getBaseEventName('BModal', 'show')` => 'bv::modal::show'
const getRootEventName = (name, eventName) => [ROOT_EVENT_NAME_PREFIX, getBaseEventName(name), eventName].join(ROOT_EVENT_NAME_SEPARATOR);

// Get a root action event name by component/directive and action name
// `getRootActionEventName('BModal', 'show')` => 'bv::show::modal'
const getRootActionEventName = (name, actionName) => [ROOT_EVENT_NAME_PREFIX, actionName, getBaseEventName(name)].join(ROOT_EVENT_NAME_SEPARATOR);

export { eventOff, eventOn, eventOnOff, getRootActionEventName, getRootEventName, parseEventOptions, stopEvent };
