import { isVue3 } from '../vue';

// Regex to detect event handler props: onSomething or onSomethingOnce
const EVENT_HANDLER_RE = /^on([A-Z][a-zA-Z]*)$/;
const ONCE_SUFFIX = 'Once';

/**
 * Converts an event name to a handler prop name.
 * Use as computed property key with event constants: [eventProp(EVENT_NAME_HIDDEN)]
 * @param {string} eventName - The event name (e.g., 'hidden', 'show', 'mouseenter')
 * @param {Object} options - Options object
 * @param {boolean} options.once - If true, returns the "once" variant (e.g., 'onHiddenOnce')
 * @returns {string} The handler prop name (e.g., 'onHidden', 'onHiddenOnce')
 */
const eventProp = function (eventName) {
  let {
    once = false
  } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  const capitalized = eventName.charAt(0).toUpperCase() + eventName.slice(1);
  return `on${capitalized}${once ? ONCE_SUFFIX : ''}`;
};

/**
 * Parses a handler prop name to extract event name and once flag.
 * Examples:
 *   onShow -> { eventName: 'show', once: false }
 *   onShowOnce -> { eventName: 'show', once: true }
 *   onMouseenter -> { eventName: 'mouseenter', once: false }
 */
const parseEventHandlerProp = propName => {
  const match = propName.match(EVENT_HANDLER_RE);
  if (!match) return null;
  let eventPart = match[1];
  const once = eventPart.endsWith(ONCE_SUFFIX);
  if (once) eventPart = eventPart.slice(0, -ONCE_SUFFIX.length);
  const eventName = eventPart.charAt(0).toLowerCase() + eventPart.slice(1);
  return {
    eventName,
    once
  };
};

/**
 * Extracts event handlers from config and separates them from other props.
 * @param {Object} config - The config object with potential event handler props
 * @returns {{ handlers: Array<{eventName: string, handler: Function, once: boolean}>, cleanConfig: Object }}
 */
const extractEventHandlers = config => {
  const handlers = [];
  const cleanConfig = {
    ...config
  };
  if (cleanConfig.propsData) {
    const cleanPropsData = {};
    Object.keys(cleanConfig.propsData).forEach(propName => {
      const parsed = parseEventHandlerProp(propName);
      if (parsed && typeof cleanConfig.propsData[propName] === 'function') {
        handlers.push({
          ...parsed,
          handler: cleanConfig.propsData[propName]
        });
      } else {
        cleanPropsData[propName] = cleanConfig.propsData[propName];
      }
    });
    cleanConfig.propsData = cleanPropsData;
  }
  return {
    handlers,
    cleanConfig
  };
};
const createNewChildComponent = function (parent, Component) {
  let config = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
  const bvEventRoot = parent.$root ? parent.$root.$options.bvEventRoot || parent.$root : null;

  // Vue 3: pass handlers as props directly (Vue 3 converts onXxx props to listeners)
  if (isVue3(parent)) {
    return new Component({
      ...config,
      parent,
      bvParent: parent,
      bvEventRoot
    });
  }

  // Vue 2: extract handlers and subscribe manually after creation
  const {
    handlers,
    cleanConfig
  } = extractEventHandlers(config);
  const instance = new Component({
    ...cleanConfig,
    parent,
    bvParent: parent,
    bvEventRoot
  });

  // Subscribe to events using $on/$once
  handlers.forEach(_ref => {
    let {
      eventName,
      handler,
      once
    } = _ref;
    instance[once ? '$once' : '$on'](eventName, handler);
  });
  return instance;
};

export { createNewChildComponent, eventProp };
