'use strict';

const globalSlimmerRegistry = require('./global-slimmer-registry-b3bce7e0.js');
const observer = require('./observer-f49483e8.js');
const changeManager = require('./change-manager-a297e4d2.js');
const ui = require('./ui-3727d685.js');
const domNodeSubjectObserverFactory = require('./dom-node-subject-observer-factory-ba6a95f3.js');
const vegaInternalEventId = require('./vega-internal-event-id-87014e4f.js');

var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
  return c > 3 && r && Object.defineProperty(target, key, r), r;
};
/**
 * The subState observer that to sync up the parent state to the children components.
 */
class SubStateObserverSlimmer extends globalSlimmerRegistry.VegaSlimmer {
  /**
   * @param {SubStateObserverEntry} observerEntry - observerEntry is the object that contains the parent state and the state name.
   */
  constructor(observerEntry) {
    super();
    /**
     * The function checks if the input object has a 'host' property that matches the parent host and a 'stateName' property.
     *
     * @param {unknown} input - The `input` parameter is of type `unknown`, which means it can be any type.
     * @returns {boolean} a boolean value indicating whether the input is an acceptable observer payload.
     */
    this.isAcceptableObserverPayload = (input) => {
      return typeof input === 'object' && !!input && input['host'] === this.parent;
    };
    this.observerEntry = observerEntry;
  }
  /**
   * Initialize the subState observer.
   */
  connectedCallback() {
    this.parent = this.getParent();
    if (!this.parent)
      return;
    const { subStates } = this.observerEntry;
    this.subStateObserver = new observer.Observer(this.isAcceptableObserverPayload, (payload) => {
      const subState = subStates.find((subState) => subState.parentStateName === payload.stateName);
      if (subState) {
        this.updateState(subState, payload.value);
      }
    });
    changeManager.ChangeManager.register(domNodeSubjectObserverFactory.domNodeSubjectFactory.getSubject(this.parent, vegaInternalEventId.VegaInternalSubStatePush), this.subStateObserver);
    if (this.observerEntry.pullStatesWhenReattached && this.host.classList.contains('hydrated')) {
      this.parent = this.getParent();
      this.pullStates();
    }
  }
  /**
   * Unregister the observer when disconnectedCallback
   */
  disconnectedCallback() {
    if (!this.parent)
      return;
    changeManager.ChangeManager.unregister(domNodeSubjectObserverFactory.domNodeSubjectFactory.getSubject(this.parent, vegaInternalEventId.VegaInternalSubStatePush), this.subStateObserver);
  }
  /**
   * Fetch the parent props when componentWillLoad
   */
  componentWillLoad() {
    this.pullStates();
  }
  /**
   * The function `getParent` returns the parent element of a given host element, based on the observer
   * entry and appender element.
   *
   * @returns {Nullable<HTMLElement>} the parent HTMLElement.
   */
  getParent() {
    if (typeof this.observerEntry.parent === 'string') {
      return ui.findParent(this.host, this.observerEntry.parent);
    }
    else {
      return this.observerEntry.parent();
    }
  }
  /**
   * Update the state with new value
   *
   * @param {SubStateEntry} subState - current state entry
   * @param {unknown} value - new value
   */
  updateState(subState, value) {
    if (subState.callback) {
      subState.callback(value);
    }
    else {
      this[subState.subStateName] = value;
    }
  }
  /**
   * The `pullStates` function iterates through subStates and notifies the ChangeManager to update the
   * state based on the callback function provided.
   *
   * @returns {void} If the `this.parent` property is falsy, the `pullStates` method will return early and not
   * execute the rest of the code inside the method.
   */
  pullStates() {
    if (!this.parent)
      return;
    const { subStates } = this.observerEntry;
    subStates.forEach((subState) => {
      changeManager.ChangeManager.notify(domNodeSubjectObserverFactory.domNodeSubjectFactory.getSubject(this.parent, vegaInternalEventId.VegaInternalSubStatePull), {
        host: this.parent,
        stateName: subState.parentStateName,
        // eslint-disable-next-line jsdoc/require-jsdoc
        callback: (value) => {
          this.updateState(subState, value);
        },
      });
    });
  }
}
__decorate([
  globalSlimmerRegistry.MapToComponentField()
], SubStateObserverSlimmer.prototype, "host", void 0);
__decorate([
  globalSlimmerRegistry.MapToComponentMethod('connectedCallback')
], SubStateObserverSlimmer.prototype, "connectedCallback", null);
__decorate([
  globalSlimmerRegistry.MapToComponentMethod('disconnectedCallback')
], SubStateObserverSlimmer.prototype, "disconnectedCallback", null);
__decorate([
  globalSlimmerRegistry.MapToComponentMethod('componentWillLoad')
], SubStateObserverSlimmer.prototype, "componentWillLoad", null);

exports.SubStateObserverSlimmer = SubStateObserverSlimmer;
