var __decorate = (this && this.__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;
};
import { MapToComponentField, MapToComponentMethod, VegaSlimmer } from 'vega-slimmer/core';
import { LogUtility } from '../../../../utils/log';
import { forceUpdate } from '@stencil/core';
import ChangeManager from '../../../../helpers/change-manager/change-manager';
import { TABLE_EXPAND_ROW } from '../../../../helpers/change-manager/subject/static-subject/static-subject-title';
import { Observer } from '../../../../helpers/change-manager/observer/observer';
import { findParent } from '../../../../utils/ui';
import domNodeSubjectFactory from '../../../../helpers/change-manager/subject/dom-node-subject/dom-node-subject-factory';
import remoteInvocationRegistry from '../../../../helpers/remote-invocation/remote-invocation-registry';
import { VegaInternalTableRowExpand } from '../../../../helpers/event-manager/event-id/vega-internal-event-id';
/**
 * The expand row controller of VegaTable
 */
export class VegaTableExpandRowController extends VegaSlimmer {
  constructor() {
    super(...arguments);
    /**
     * Toggle expandable row by rowKey
     *
     * @param {string} rowKey - The row key of the row
     */
    this.toggleExpandRow = (rowKey) => {
      this.isRowExpandable(rowKey) && this.handleToggleExpandRow(rowKey, !this.isExpanded(rowKey));
    };
    /**
     * Open expandable row by rowKey
     *
     * @param {string} rowKey - The row key of the row
     */
    this.openExpandRow = (rowKey) => {
      this.isRowExpandable(rowKey) && this.handleToggleExpandRow(rowKey, true);
    };
    /**
     * Close expanded row by rowKey
     *
     * @param {string} rowKey - The row key of the row
     */
    this.closeExpandRow = (rowKey) => {
      this.isRowExpandable(rowKey) && this.handleToggleExpandRow(rowKey, false);
    };
    /**
     * Close all expanded row
     */
    this.closeAllExpandRow = () => {
      this.hasExpandableRow && this.handleCloseAllExpandRow();
    };
    /**
     * Whether the row is expandable
     *
     * @param {VegaTableDataSourceItem} row - The row data
     * @returns {boolean} Return true if the row is expandable
     */
    this.isExpandableRow = (row) => {
      return this.expandableRows.includes(this.vegaTableDataSourceController.getRecordKey(row));
    };
    /**
     * Whether the row is expandable
     *
     * @param {string} rowKey - The row key of the row
     * @returns {boolean} Return true if the row is expandable
     */
    this.isExpanded = (rowKey) => {
      return this.expandedRowKeySet.has(rowKey);
    };
    /**
     * Close all expand row
     */
    this.handleCloseAllExpandRow = () => {
      this.expandedRowKeySet.toArray().forEach((rowKey) => {
        ChangeManager.notify(TABLE_EXPAND_ROW, {
          host: this.host,
          rowKey: rowKey,
          expanded: false,
        });
      });
      this.expandedRowKeySet.clear();
    };
    /**
     * Toggle expand row
     *
     * @param {string} rowKey - The row key of the row
     * @param {boolean} open - set open true if you want to open the expand row, otherwise false
     */
    this.handleToggleExpandRow = (rowKey, open) => {
      if (open) {
        this.expandedRowKeySet.add(rowKey);
      }
      else {
        this.expandedRowKeySet.delete(rowKey);
      }
      ChangeManager.notify(TABLE_EXPAND_ROW, {
        host: this.host,
        rowKey: rowKey,
        expanded: open,
      });
    };
    /*
     * The below method is e2e-test covered in
     *
     * @see{module:vega-table-new-slot-content-change}
     * @see{module:vega-table-wrong-slot-content-change}
     */
    /* istanbul ignore next */
    /**
     * Init the mutation observer of expand row slot
     */
    this.initMutationObserver = () => {
      this.mutationObserver = new MutationObserver(async (mutations) => {
        const needForceUpdate = this.expandRowSlotGuard(mutations);
        if (needForceUpdate) {
          forceUpdate(this.host);
        }
      });
      this.mutationObserver.observe(this.host, { childList: true, subtree: true });
    };
    /*
     * The below method is e2e-test covered in
     * @see{module:vega-table-new-slot-content-change}
     * @see{module:vega-table-wrong-slot-content-change}
     */
    /* istanbul ignore next */
    /**
     * Monitoring the slot children used for expanded row
     *
     * @param {MutationRecord[]} mutations - The mutations of the observer
     * @returns {boolean} return true if it needs force update
     */
    this.expandRowSlotGuard = (mutations) => {
      const expectSlotNames = this.vegaTableDataSourceController
        .getCurrentData()
        .map((item) => `${VegaTableExpandRowController.expandRowSlotNamePrefix}${this.vegaTableDataSourceController.getRecordKey(item)}`);
      const expandRowSlotList = [];
      for (let i = 0; i < mutations.length; i++) {
        const slotNodes = Array.from(mutations[i].addedNodes).filter((item) => item instanceof HTMLElement && item.getAttribute('slot'));
        slotNodes.forEach((item) => {
          item.removeAttribute('hidden'); // node doesn't have a slot home to go to, so will be hidden  https://github.com/ionic-team/stencil/blob/main/src/runtime/vdom/vdom-render.ts#L964
          const slotName = item.getAttribute('slot');
          if (expectSlotNames.includes(slotName)) {
            expandRowSlotList.push(item);
          }
          else {
            LogUtility.warn(`The vega-table expand row slot name '${slotName}' is not as expected, it must be like: vega-table-expand-row-[rowKey]`);
          }
        });
      }
      return expandRowSlotList.length > 0;
    };
  }
  /**
   * Component lifecycle - connectedCallback
   */
  connectedCallback() {
    this.initRowExpandObserver();
  }
  /**
   * Component lifecycle - disconnectedCallback
   */
  disconnectedCallback() {
    if (this.mutationObserver) {
      this.mutationObserver.disconnect();
    }
    ChangeManager.unregister(TABLE_EXPAND_ROW, this.expandObserver);
    remoteInvocationRegistry.unRegister(domNodeSubjectFactory.getSubject(this.host, VegaInternalTableRowExpand));
  }
  /**
   * Component lifecycle - componentWillLoad
   */
  componentWillLoad() {
    this.setExpandableRows();
  }
  /**
   * Component lifecycle - componentDidLoad
   */
  componentDidLoad() {
    this.initMutationObserver();
  }
  /**
   * The callback to handle [watchRowExpandable]{@link VegaTable.watchRowExpandable}
   */
  watchRowExpandable() {
    this.setExpandableRows();
    this.handleCloseAllExpandRow();
  }
  /**
   * Set the expandable rows based on the rowExpandable prop
   */
  watchCurrentData() {
    this.setExpandableRows();
    this.clearUnusedExpandRowSlot();
  }
  /**
   * Initializes row expand observer
   */
  initRowExpandObserver() {
    this.expandObserver = new Observer(this.isAcceptableTableRowObserver.bind({ host: this.host }), (payload) => {
      if (payload.expanded) {
        this.expandedRowKeySet.add(payload.rowKey);
      }
      else {
        this.expandedRowKeySet.delete(payload.rowKey);
      }
    });
    ChangeManager.register(TABLE_EXPAND_ROW, this.expandObserver);
    remoteInvocationRegistry.register(domNodeSubjectFactory.getSubject(this.host, VegaInternalTableRowExpand), ({ rowKey, expanded }) => {
      return this.rowExpandEventEmitter.emit({
        record: this.vegaTableDataSourceController.getRecordByKey(rowKey),
        expanded: expanded,
      });
    });
  }
  /**
   * The function checks if the input is an acceptable row observer.
   *
   * @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 acceptable observer.
   */
  isAcceptableTableRowObserver(input) {
    return (input['host']['tagName'] === 'VEGA-TABLE-ROW' &&
      this.host === findParent(input['host'], 'vega-table'));
  }
  /**
   * Sets expandable rows and hasExpandableRow based on rowExpandable and currentData
   */
  setExpandableRows() {
    if (typeof this.rowExpandable === 'boolean') {
      this.expandableRows = this.rowExpandable
        ? this.currentData.map((item) => this.vegaTableDataSourceController.getRecordKey(item))
        : [];
      this.hasExpandableRow = this.rowExpandable;
    }
    else if (typeof this.rowExpandable === 'function') {
      const result = [];
      this.currentData.forEach((item) => {
        const rowKey = this.vegaTableDataSourceController.getRecordKey(item);
        if (this.rowExpandable(rowKey)) {
          result.push(rowKey);
        }
      });
      this.expandableRows = result;
      this.hasExpandableRow = result.length > 0;
    }
    else {
      this.expandableRows = [];
      this.hasExpandableRow = false;
    }
  }
  /**
   * Whether the row is expandable by rowKey
   *
   * @param {string} rowKey - The row key of the row
   * @returns {boolean} Return true if the row is expandable
   */
  isRowExpandable(rowKey) {
    return this.expandableRows.includes(rowKey);
  }
  /**
   * Clear the expand row slot which is not expandable anymore to avoid confusion,
   *    this can be triggered by the change of rowExpandable or currentData
   */
  clearUnusedExpandRowSlot() {
    this.expandedRowKeySet.toArray().forEach((rowKey) => {
      if (!this.isRowExpandable(rowKey)) {
        this.expandedRowKeySet.delete(rowKey);
      }
    });
  }
}
VegaTableExpandRowController.expandRowSlotNamePrefix = 'vega-table-expand-row-';
__decorate([
  MapToComponentField()
], VegaTableExpandRowController.prototype, "host", void 0);
__decorate([
  MapToComponentField()
], VegaTableExpandRowController.prototype, "expandedRowKeySet", void 0);
__decorate([
  MapToComponentField({ writable: true })
], VegaTableExpandRowController.prototype, "expandableRows", void 0);
__decorate([
  MapToComponentField({ writable: true })
], VegaTableExpandRowController.prototype, "hasExpandableRow", void 0);
__decorate([
  MapToComponentField()
], VegaTableExpandRowController.prototype, "rowExpandable", void 0);
__decorate([
  MapToComponentField()
], VegaTableExpandRowController.prototype, "currentData", void 0);
__decorate([
  MapToComponentField()
], VegaTableExpandRowController.prototype, "rowExpandEventEmitter", void 0);
__decorate([
  MapToComponentField()
], VegaTableExpandRowController.prototype, "vegaTableDataSourceController", void 0);
__decorate([
  MapToComponentMethod('connectedCallback')
], VegaTableExpandRowController.prototype, "connectedCallback", null);
__decorate([
  MapToComponentMethod('disconnectedCallback')
], VegaTableExpandRowController.prototype, "disconnectedCallback", null);
__decorate([
  MapToComponentMethod('componentWillLoad')
], VegaTableExpandRowController.prototype, "componentWillLoad", null);
__decorate([
  MapToComponentMethod('componentDidLoad')
], VegaTableExpandRowController.prototype, "componentDidLoad", null);
__decorate([
  MapToComponentMethod('toggleExpandRow')
], VegaTableExpandRowController.prototype, "toggleExpandRow", void 0);
__decorate([
  MapToComponentMethod('openExpandRow')
], VegaTableExpandRowController.prototype, "openExpandRow", void 0);
__decorate([
  MapToComponentMethod('closeExpandRow')
], VegaTableExpandRowController.prototype, "closeExpandRow", void 0);
__decorate([
  MapToComponentMethod('closeAllExpandRow')
], VegaTableExpandRowController.prototype, "closeAllExpandRow", void 0);
__decorate([
  MapToComponentMethod('watchRowExpandable')
], VegaTableExpandRowController.prototype, "watchRowExpandable", null);
__decorate([
  MapToComponentMethod('watchCurrentData')
], VegaTableExpandRowController.prototype, "watchCurrentData", null);
