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 ChangeManager from '../../../../helpers/change-manager/change-manager';
import { Observer } from '../../../../helpers/change-manager/observer/observer';
import { TABLE_ROW_CLICK, TABLE_ROW_SELECTION, TABLE_ROW_SELECTION_ALL, } from '../../../../helpers/change-manager/subject/static-subject/static-subject-title';
import { findParent } from '../../../../utils/ui';
import remoteInvocationRegistry from '../../../../helpers/remote-invocation/remote-invocation-registry';
import domNodeSubjectFactory from '../../../../helpers/change-manager/subject/dom-node-subject/dom-node-subject-factory';
import { VegaInternalTableRowSelect, VegaInternalTableRowSelectAll, } from '../../../../helpers/event-manager/event-id/vega-internal-event-id';
/**
 *
 */
export class VegaTableRowSelectionController extends VegaSlimmer {
  constructor() {
    super(...arguments);
    /**
     * The method for handling row selection change
     *
     * @param {boolean} checked - true: the row is selected, otherwise not selected
     * @param {VegaTableDataSourceItem} record - The record of the changed row
     */
    this.handleRowSelect = (checked, record) => {
      const rowKey = this.vegaTableDataSourceController.getRecordKey(record);
      let isChanged = false;
      if (checked) {
        if (!this.selectedRowKeySet.has(rowKey)) {
          this.selectedRowKeySet.add(rowKey);
          isChanged = true;
        }
      }
      else {
        if (this.selectedRowKeySet.has(rowKey)) {
          this.selectedRowKeySet.delete(rowKey);
          isChanged = true;
        }
      }
      if (isChanged) {
        this.selectChangeEventEmitter.emit({
          selected: checked,
          record: record,
          selectedRows: this.getSelectedRecords(),
        });
      }
    };
    /**
     * Get the row selection type
     *
     * @returns {Nullable<'multiple' | 'single'>} Return the type of the row selection
     */
    this.getRowSelectionType = () => {
      if (!this.rowSelection)
        return;
      return this.rowSelection.type || 'multiple';
    };
    /**
     * The method for handing the single row selection
     *
     * @param {VegaTableDataSourceItem} record - The record of the single selected row
     */
    this.handleSingleRowSelect = (record) => {
      const rowKey = this.vegaTableDataSourceController.getRecordKey(record);
      if (this.isChecked(rowKey)) {
        this.handleRowSelect(false, record);
      }
      else {
        this.selectedRowKeySet.clear();
        this.handleRowSelect(true, record);
      }
    };
    /**
     * Verify the row is checked or not for row selection
     *
     * @param {string} key - The row key of the row
     * @returns {boolean} Return true if the row is selected, otherwise false
     */
    this.isChecked = (key) => {
      return this.selectedRowKeySet.has(key);
    };
    /**
     * The method to handling select all rows
     *
     * @param {boolean} checkedAll - true: all rows are selected; false: not selected all rows
     */
    this.handleSelectAll = (checkedAll) => {
      if (checkedAll) {
        const recordKeys = this.vegaTableDataSourceController.getAllRecordKeys();
        this.selectedRowKeySet.add(...recordKeys.filter((key) => !this.selectedRowKeySet.has(key)));
      }
      else {
        if (this.isCheckedAll()) {
          this.selectedRowKeySet.clear();
        }
      }
    };
    /**
     * Verify if all rows are selected
     *
     * @returns {boolean} return true if all rows are selected, otherwise false
     */
    this.isCheckedAll = () => {
      return (this.selectedRowKeySet.size > 0 &&
        this.vegaTableDataSourceController
          .getCurrentData()
          .every((record) => this.selectedRowKeySet.has(this.vegaTableDataSourceController.getRecordKey(record))));
    };
    /**
     * Set up the row selection config
     *
     * @param {VegaTableRowSelectionConfig} config - The config of the row selection
     */
    this.setupRowSelection = (config) => {
      this.rowSelection = Object.assign({ hideSelectAll: false, type: 'multiple' }, config);
    };
    /**
     * Get the selected rows records array
     *
     * @returns {VegaTableDataSourceItem[]} The array of the all selected row's records
     */
    this.getSelectedRecords = () => {
      return this.selectedRowKeySet
        .toArray()
        .map(this.vegaTableDataSourceController.getRecordByKey)
        .filter(Boolean);
    };
    /**
     * Sync up the selected row's key when current data changed
     *
     * @param {VegaTableDataSourceItem[]} currentData - The current data of the source
     */
    this.syncUpSelectedKeySetWithCurrentData = (currentData) => {
      this.selectedRowKeySet.withMutation((set) => {
        set.clear();
        currentData.forEach((item) => {
          const rowKey = this.vegaTableDataSourceController.getRecordKey(item);
          if (this.selectedRowKeySet.has(rowKey)) {
            set.add(rowKey);
          }
        });
      });
    };
  }
  /**
   * Component lifecycle - connectedCallback
   */
  connectedCallback() {
    this.initRowSelection();
    this.initRowClickObserver();
    this.initRowSelectionAllObserver();
  }
  /**
   *
   */
  disconnectedCallback() {
    ChangeManager.unregister(TABLE_ROW_SELECTION, this.rowSelectionObserver);
    ChangeManager.unregister(TABLE_ROW_SELECTION_ALL, this.rowSelectionAllObserver);
    ChangeManager.unregister(TABLE_ROW_CLICK, this.rowClickObserver);
    remoteInvocationRegistry.unRegister(domNodeSubjectFactory.getSubject(this.host, VegaInternalTableRowSelect));
    remoteInvocationRegistry.unRegister(domNodeSubjectFactory.getSubject(this.host, VegaInternalTableRowSelectAll));
  }
  /**
   * Component lifecycle - componentWillLoad
   */
  componentWillLoad() {
    if (this.rowSelection) {
      this.setupRowSelection(this.rowSelection);
    }
  }
  /**
   * The callback to handle [watchRowSelection]{@link VegaTable.watchRowSelection}
   *
   * @param {VegaTableRowSelectionConfig} newValue - The changed value of rowSelection
   * @param {VegaTableRowSelectionConfig} oldValue - The value of rowSelection before changing
   */
  watchRowSelection(newValue, oldValue) {
    if ((oldValue === null || oldValue === void 0 ? void 0 : oldValue.type) !== (newValue === null || newValue === void 0 ? void 0 : newValue.type)) {
      void this.clearSelection();
    }
  }
  /**
   * The callback to handle [setSelection]{@link VegaTable.setSelection}
   *
   * @param {string[]} keys - The keys array of which you want to select
   */
  setSelection(keys) {
    if (this.getRowSelectionType() === 'single') {
      keys.splice(1);
    }
    this.selectedRowKeySet.toArray().forEach((key) => {
      ChangeManager.notify(TABLE_ROW_SELECTION, {
        host: this.host,
        rowKey: key,
        checked: false,
      });
    });
    this.selectedRowKeySet.clear();
    keys.forEach((key) => {
      if (this.vegaTableDataSourceController.getRecordByKey(key)) {
        this.selectedRowKeySet.add(key);
        ChangeManager.notify(TABLE_ROW_SELECTION, {
          host: this.host,
          rowKey: key,
          checked: true,
        });
      }
    });
  }
  /**
   * The callback to handle [watchCurrentData]{@link VegaTable.watchCurrentData}
   *
   * @param {VegaTableDataSourceItem} currentData - The changed value of currentData
   */
  watchCurrentData(currentData) {
    this.syncUpSelectedKeySetWithCurrentData(currentData);
  }
  /**
   * The callback to handle [clearSelection]{@link VegaTable.clearSelection}
   */
  clearSelection() {
    this.selectedRowKeySet.clear();
    ChangeManager.notify(TABLE_ROW_SELECTION_ALL, {
      host: this.host,
      checked: false,
      noneChecked: this.selectedRowKeySet.size === 0,
    });
  }
  /**
   * The callback to handle [getSelection]{@link VegaTable.getSelection}
   *
   * @returns {string[]} The selected row keys array
   */
  getSelection() {
    return this.selectedRowKeySet.toArray();
  }
  /**
   *
   */
  watchSelectedRowKeySet() {
    this.isSelectedAll = this.isCheckedAll();
  }
  /**
   *
   */
  watchSelectedAll() {
    ChangeManager.notify(TABLE_ROW_SELECTION_ALL, {
      host: this.host,
      checked: this.isCheckedAll(),
      noneChecked: this.selectedRowKeySet.size === 0,
    });
    this.selectAllChangeEventEmitter.emit({
      selected: this.isCheckedAll(),
      selectedRows: this.getSelectedRecords(),
    });
  }
  /**
   * The function checks if the input is an acceptable table row observer by verifying its host tag name and ensuring it is a child of a vega-table element.
   *
   * @param {unknown} input - The `input` parameter is of type `unknown`, which means it can be any type.
   * @returns {boolean} boolean value indicating whether the input is of type T and satisfies certain conditions.
   */
  isAcceptableRowSelectionObserver(input) {
    if (input['host']['tagName'] === 'VEGA-TABLE') {
      return this.host === input['host'];
    }
    if (input['host']['tagName'] === 'VEGA-TABLE-ROW') {
      return this.host === findParent(input['host'], 'vega-table');
    }
  }
  /**
   * The function checks if the input is an acceptable observer for a table head row in a Vega table.
   *
   * @param {unknown} input - The `input` parameter is of type `unknown`, which means it can be any type.
   * @returns {boolean}  boolean value.
   */
  isAcceptableRowSelectionAllObserver(input) {
    if (input['host']['tagName'] === 'VEGA-TABLE') {
      return this.host === input['host'];
    }
    if (input['host']['tagName'] === 'VEGA-TABLE-HEAD-ROW') {
      return this.host === findParent(input['host'], 'vega-table');
    }
  }
  /**
   * The function initializes a row selection.
   */
  initRowSelection() {
    this.rowSelectionObserver = new Observer(this.isAcceptableRowSelectionObserver.bind(this), (payload) => {
      const { rowKey, checked } = payload;
      const record = this.vegaTableDataSourceController.getRecordByKey(rowKey);
      this.handleRowSelect(checked, record);
    });
    ChangeManager.register(TABLE_ROW_SELECTION, this.rowSelectionObserver);
    remoteInvocationRegistry.register(domNodeSubjectFactory.getSubject(this.host, VegaInternalTableRowSelect), ({ rowKey, checked }) => {
      return this.rowSelectEventEmitter.emit({
        selected: checked,
        record: this.vegaTableDataSourceController.getRecordByKey(rowKey),
        selectedRows: this.getSelectedRecords(),
      });
    });
    remoteInvocationRegistry.register(domNodeSubjectFactory.getSubject(this.host, VegaInternalTableRowSelectAll), ({ checked }) => {
      return this.rowSelectAllEventEmitter.emit({
        selected: checked,
        selectedRows: this.getSelectedRecords(),
        changedRows: checked
          ? this.vegaTableDataSourceController
            .getCurrentData()
            .filter((record) => !this.selectedRowKeySet.has(record.key))
          : this.getSelectedRecords(),
      });
    });
  }
  /**
   * The function initializes an observer for row selection all in a table
   */
  initRowSelectionAllObserver() {
    this.rowSelectionAllObserver = new Observer(this.isAcceptableRowSelectionAllObserver.bind(this), (payload) => {
      this.handleSelectAll(payload.checked);
    });
    ChangeManager.register(TABLE_ROW_SELECTION_ALL, this.rowSelectionAllObserver);
  }
  /**
   * The function initializes a row click observer that handles row selection in a table.
   */
  initRowClickObserver() {
    this.rowClickObserver = new Observer(this.isAcceptableRowClickObserver.bind(this), (payload) => {
      if (this.getRowSelectionType() === 'single') {
        const record = this.vegaTableDataSourceController.getRecordByKey(payload.rowKey);
        this.handleSingleRowSelect(record);
      }
    });
    ChangeManager.register(TABLE_ROW_CLICK, this.rowClickObserver);
  }
  /**
   * The function checks if the input is an acceptable row click 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.
   */
  isAcceptableRowClickObserver(input) {
    return (input['host']['tagName'] === 'VEGA-TABLE-ROW' &&
      this.host === findParent(input['host'], 'vega-table'));
  }
}
__decorate([
  MapToComponentField()
], VegaTableRowSelectionController.prototype, "host", void 0);
__decorate([
  MapToComponentField({ writable: true })
], VegaTableRowSelectionController.prototype, "isSelectedAll", void 0);
__decorate([
  MapToComponentField()
], VegaTableRowSelectionController.prototype, "selectedRowKeySet", void 0);
__decorate([
  MapToComponentField({ writable: true })
], VegaTableRowSelectionController.prototype, "rowSelection", void 0);
__decorate([
  MapToComponentField()
], VegaTableRowSelectionController.prototype, "rowKey", void 0);
__decorate([
  MapToComponentField()
], VegaTableRowSelectionController.prototype, "selectChangeEventEmitter", void 0);
__decorate([
  MapToComponentField()
], VegaTableRowSelectionController.prototype, "selectAllChangeEventEmitter", void 0);
__decorate([
  MapToComponentField()
], VegaTableRowSelectionController.prototype, "vegaTableDataSourceController", void 0);
__decorate([
  MapToComponentField()
], VegaTableRowSelectionController.prototype, "rowSelectEventEmitter", void 0);
__decorate([
  MapToComponentField()
], VegaTableRowSelectionController.prototype, "rowSelectAllEventEmitter", void 0);
__decorate([
  MapToComponentMethod('connectedCallback')
], VegaTableRowSelectionController.prototype, "connectedCallback", null);
__decorate([
  MapToComponentMethod('disconnectedCallback')
], VegaTableRowSelectionController.prototype, "disconnectedCallback", null);
__decorate([
  MapToComponentMethod('componentWillLoad')
], VegaTableRowSelectionController.prototype, "componentWillLoad", null);
__decorate([
  MapToComponentMethod('watchRowSelection')
], VegaTableRowSelectionController.prototype, "watchRowSelection", null);
__decorate([
  MapToComponentMethod('setSelection')
], VegaTableRowSelectionController.prototype, "setSelection", null);
__decorate([
  MapToComponentMethod('watchCurrentData')
], VegaTableRowSelectionController.prototype, "watchCurrentData", null);
__decorate([
  MapToComponentMethod('clearSelection')
], VegaTableRowSelectionController.prototype, "clearSelection", null);
__decorate([
  MapToComponentMethod('getSelection')
], VegaTableRowSelectionController.prototype, "getSelection", null);
__decorate([
  MapToComponentMethod('watchSelectedRowKeySet')
], VegaTableRowSelectionController.prototype, "watchSelectedRowKeySet", null);
__decorate([
  MapToComponentMethod('watchSelectedAll')
], VegaTableRowSelectionController.prototype, "watchSelectedAll", null);
