import { compose } from '../helpers';
import { componentNameValidationMixin } from '../mixins/componentNameValidationMixin';
import { componentsContextMixin } from '../mixins/componentsContextMixin';
import { hoverableMixin } from '../mixins/hoverableMixin';
import { normalizeBooleanAttributesMixin } from '../mixins/normalizeBooleanAttributesMixin';

export const createBaseClass = ({ componentName, baseSelector = '' }) => {
  class DescopeBaseClass extends HTMLElement {
    static get componentName() {
      return componentName;
    }

    #baseElement;

    #isInit = true;

    // base selector is the selector for the component wrapper,
    // it's the highest element that is relevant for the layout
    // eslint-disable-next-line class-methods-use-this
    get baseSelector() {
      return baseSelector;
    }

    // this is the base element, which returned by querying the base selector
    get baseElement() {
      this.#baseElement ??= this.baseSelector
        ? this.rootElement.querySelector(this.baseSelector)
        : this;

      if (!this.#baseElement) {
        // eslint-disable-next-line no-console
        console.warn('missing base element for component', this.localName);
      }
      return this.#baseElement;
    }

    // this is the component root level element,
    // it can be either a shadow root or the component's node from the light DOM
    get rootElement() {
      return this.shadowRoot || this;
    }

    get name() {
      return this.getAttribute('name');
    }

    connectedCallback() {
      super.connectedCallback?.();

      if (this.rootElement.isConnected) {
        // the init function is running once, on the first time the component is connected
        if (this.#isInit) {
          this.#isInit = false;
          this.init?.();
        }
      }
    }
  }

  return compose(
    componentNameValidationMixin,
    hoverableMixin,
    normalizeBooleanAttributesMixin,
    componentsContextMixin
  )(DescopeBaseClass);
};
