import { injectStyle } from '@descope-ui/common/components-helpers';
import { createBaseClass } from '../baseClasses/createBaseClass';
import { isFunction } from '../helpers';
import { forwardProps, syncAttrs } from '../helpers/componentHelpers';
import { createDispatchEvent } from '../helpers/mixinsHelpers';

export const createProxy = ({
  componentName,
  wrappedEleName,
  slots = [],
  style,
  excludeAttrsSync = [],
  includeAttrsSync = [],
  includeForwardProps = [],
  delegatesFocus = true,
}) => {
  class ProxyClass extends createBaseClass({ componentName, baseSelector: wrappedEleName }) {
    #dispatchBlur = createDispatchEvent.bind(this, 'blur');

    #dispatchFocus = createDispatchEvent.bind(this, 'focus');

    constructor() {
      super().attachShadow({ mode: 'open', delegatesFocus }).innerHTML = `
			<${wrappedEleName}>
			${slots
        .map(
          (
            slot // when slot is an empty string, we will create the default slot (without a name)
          ) => `<slot ${slot ? `name="${slot}" slot="${slot}"` : ''}></slot>`
        )
        .join('')}
			</${wrappedEleName}>
		`;

      injectStyle((isFunction(style) ? style() : style) || '', this);
    }

    init() {
      super.init?.();

      this.baseElement.addEventListener('blur', (_) => {
        this.#dispatchBlur();
      });

      this.baseElement.addEventListener('focus', (_) => {
        this.#dispatchFocus();
      });

      // this is needed for components that uses props, such as combo box
      forwardProps(this.baseElement, this, includeForwardProps);

      syncAttrs(this.baseElement, this, {
        excludeAttrs: excludeAttrsSync,
        includeAttrs: includeAttrsSync,
      });
    }
  }

  return ProxyClass;
};
