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 { generateUUID } from '../../../../utils/misc';
import { LogUtility } from '../../../../utils/log';
/**
 * Edit table controller
 */
export class VegaTableEditableController extends VegaSlimmer {
  constructor() {
    super(...arguments);
    this.rowFormRefMap = new Map();
  }
  /**
   * Get the map of the row form refs
   *
   * @returns {Map<string, HTMLVegaFormElement>} The map of row form refs
   */
  getRowFormRefMap() {
    return this.rowFormRefMap;
  }
  /**
   * The callback to handle [saveAllEditRows]{@link VegaTable.saveAllEditRows}
   */
  async saveAllEditRows() {
    if (!this.canMethodBeInvokedInCurrentState('saveAllEditRows')) {
      return;
    }
    const currentData = this.vegaTableDataSourceController
      .getCurrentData()
      .slice();
    for (const rowKey of this.editingRows.toArray()) {
      const rowData = await this.getRowData(rowKey);
      const index = currentData.findIndex((item) => this.vegaTableDataSourceController.getRecordKey(item) === rowKey);
      if (index > -1) {
        currentData.splice(index, 1, rowData);
      }
    }
    this.vegaTableDataSourceController.setDataSource([...currentData]);
    void this.stopAllRowEditMode();
  }
  /**
   * The callback to handle [stopAllRowEditMode]{@link VegaTable.stopAllRowEditMode}
   */
  stopAllRowEditMode() {
    if (!this.canMethodBeInvokedInCurrentState('stopAllRowEditMode')) {
      return;
    }
    this.editingRows.clear();
  }
  /**
   * Stop the removed editing row when the data source changed
   *
   * @param {VegaTableDataSourceItem[]} newValue - The new data source
   */
  watchDataSource(newValue) {
    if (this.isEditableTable()) {
      this.getEditingRowsKey().forEach((rowKey) => {
        if (!newValue.find((item) => item.key === rowKey)) {
          this.stopRowEditMode(rowKey);
        }
      });
    }
  }
  /**
   * The callback to handle [saveEditRow]{@link VegaTable.saveEditRow}
   *
   * @param {string} rowKey - The key of the row's record
   */
  async saveEditRow(rowKey) {
    if (!this.canMethodBeInvokedInCurrentState('saveEditRow')) {
      return;
    }
    const rowData = await this.getRowData(rowKey);
    const currentData = this.vegaTableDataSourceController
      .getCurrentData()
      .slice();
    const index = currentData.findIndex((item) => this.vegaTableDataSourceController.getRecordKey(item) === rowKey);
    if (index > -1) {
      currentData.splice(index, 1, rowData);
      this.vegaTableDataSourceController.setDataSource([...currentData]);
    }
    void this.stopRowEditMode(rowKey);
  }
  /**
   * The callback to handle [stopRowEditMode]{@link VegaTable.stopRowEditMode}
   *
   * @param {string} rowKey - The key of the row's record
   */
  stopRowEditMode(rowKey) {
    if (!this.canMethodBeInvokedInCurrentState('stopRowEditMode')) {
      return;
    }
    this.editingRows.delete(rowKey);
  }
  /**
   * The callback to handle [removeRow]{@link VegaTable.removeRow}
   *
   * @param {string} rowKey - The key of the row's record
   */
  removeRow(rowKey) {
    if (!this.canMethodBeInvokedInCurrentState('removeRow')) {
      return;
    }
    this.vegaTableDataSourceController.setDataSource(this.vegaTableDataSourceController
      .getCurrentData()
      .filter((item) => this.vegaTableDataSourceController.getRecordKey(item) !== rowKey));
  }
  /**
   * The callback to handle [startRowEditMode]{@link VegaTable.startRowEditMode}
   *
   * @param {string} rowKey - The key of the row's record
   */
  startRowEditMode(rowKey) {
    if (!this.canMethodBeInvokedInCurrentState('startRowEditMode')) {
      return;
    }
    this.editingRows.add(rowKey);
  }
  /**
   * The callback to handle [addNewRow]{@link VegaTable.addNewRow}
   *
   * @param {VegaTableDataSourceItem} record - The record for adding
   * @returns {string} The rowKey of the new added row record
   */
  addNewRow(record = {}) {
    var _a;
    if (!this.canMethodBeInvokedInCurrentState('addNewRow')) {
      return;
    }
    const rowKey = ((_a = record[this.rowKey]) === null || _a === void 0 ? void 0 : _a.toString()) || generateUUID();
    const newRowItem = Object.assign({}, record);
    newRowItem[this.rowKey] = rowKey;
    this.vegaTableDataSourceController.setCurrentData([
      ...this.vegaTableDataSourceController.getCurrentData(),
      newRowItem,
    ]);
    this.editingRows.add(rowKey);
    return rowKey;
  }
  /**
   * The callback to handle [getRowsData]{@link VegaTable.getRowsData}
   */
  async getRowsData() {
    if (!this.canMethodBeInvokedInCurrentState('getRowsData')) {
      return;
    }
    const tableFormRef = this.vegaTableBodyRenderer.getTableFormRef();
    const formValues = tableFormRef ? await tableFormRef.getValue() : [];
    return [
      ...this.vegaTableDataSourceController.getCurrentData().map((record) => {
        const value = formValues[`${VegaTableEditableController.rowFormKeyPrefix}${this.vegaTableDataSourceController.getRecordKey(record)}`];
        return Object.assign(Object.assign({}, record), value);
      }),
    ];
  }
  /**
   * The callback to handle [getEditingRowsKey]{@link VegaTable.getEditingRowsKey}
   *
   * @returns {string[]} The key of the rows which is editing
   */
  getEditingRowsKey() {
    if (!this.canMethodBeInvokedInCurrentState('getEditingRowsKey')) {
      return;
    }
    return this.editingRows.toArray();
  }
  /**
   * The callback to handle [getFormRef]{@link VegaTable.getFormRef}
   *
   * @param {string} rowKey - The key of the row's record
   * @returns {HTMLVegaFormElement} The form ref of the row
   */
  getFormRef(rowKey) {
    if (!this.canMethodBeInvokedInCurrentState('getFormRef')) {
      return;
    }
    return rowKey ? this.rowFormRefMap.get(rowKey) : this.vegaTableBodyRenderer.getTableFormRef();
  }
  /**
   * The callback to handle [getRowData]{@link VegaTable.getRowData}
   *
   * @param {string} rowKey - The key of the row's record
   * @returns {Promise<VegaTableDataSourceItem>} The promise of the row data
   */
  async getRowData(rowKey) {
    if (!this.canMethodBeInvokedInCurrentState('getRowData')) {
      return;
    }
    const formValue = await this.rowFormRefMap.get(rowKey).getValue();
    return Object.assign(Object.assign({}, this.vegaTableDataSourceController.getRecordByKey(rowKey)), formValue);
  }
  /**
   * Whether the row is in editing status
   *
   * @param {string} rowKey - The key of the row's record
   * @returns {boolean} return true if the row is in editing status, otherwise false
   */
  isEditing(rowKey) {
    return this.editingRows.has(rowKey);
  }
  /**
   * The function `isEditableTable` checks if any column in a table is editable.
   *
   * @returns {boolean} The `isEditableTable` method is returning a boolean value. It checks if any of the columns
   * in the `columns` array have the `editable` property set to true. If at least one column is editable,
   * the method returns `true`, otherwise it returns `false`.
   */
  isEditableTable() {
    return this.columns.some((item) => item.editable);
  }
  /**
   * The function `canMethodBeInvokedInCurrentState` checks if the table is editable and logs a warning message if not.
   *
   * @param {string} methodName - The `methodName` parameter is a string that represents the name of the
   * method being processed in the `canMethodBeInvokedInCurrentState` function.
   * @returns {boolean} The method `canMethodBeInvokedInCurrentState` is returning a boolean value. If the table is not editable,
   * it will log a warning message and return `false`. Otherwise, it will return `true`.
   */
  canMethodBeInvokedInCurrentState(methodName) {
    if (!this.isEditableTable()) {
      LogUtility.warn(`Method ${methodName} only works with editable tables`);
      return false;
    }
    return true;
  }
}
VegaTableEditableController.rowFormKeyPrefix = 'vega-table-row-form-';
__decorate([
  MapToComponentField()
], VegaTableEditableController.prototype, "editingRows", void 0);
__decorate([
  MapToComponentField()
], VegaTableEditableController.prototype, "rowKey", void 0);
__decorate([
  MapToComponentField()
], VegaTableEditableController.prototype, "columns", void 0);
__decorate([
  MapToComponentField()
], VegaTableEditableController.prototype, "vegaTableDataSourceController", void 0);
__decorate([
  MapToComponentField()
], VegaTableEditableController.prototype, "vegaTableBodyRenderer", void 0);
__decorate([
  MapToComponentMethod('saveAllEditRows')
], VegaTableEditableController.prototype, "saveAllEditRows", null);
__decorate([
  MapToComponentMethod('stopAllRowEditMode')
], VegaTableEditableController.prototype, "stopAllRowEditMode", null);
__decorate([
  MapToComponentMethod('watchDataSource')
], VegaTableEditableController.prototype, "watchDataSource", null);
__decorate([
  MapToComponentMethod('saveEditRow')
], VegaTableEditableController.prototype, "saveEditRow", null);
__decorate([
  MapToComponentMethod('stopRowEditMode')
], VegaTableEditableController.prototype, "stopRowEditMode", null);
__decorate([
  MapToComponentMethod('removeRow')
], VegaTableEditableController.prototype, "removeRow", null);
__decorate([
  MapToComponentMethod('startRowEditMode')
], VegaTableEditableController.prototype, "startRowEditMode", null);
__decorate([
  MapToComponentMethod('addNewRow')
], VegaTableEditableController.prototype, "addNewRow", null);
__decorate([
  MapToComponentMethod('getRowsData')
], VegaTableEditableController.prototype, "getRowsData", null);
__decorate([
  MapToComponentMethod('getEditingRowsKey')
], VegaTableEditableController.prototype, "getEditingRowsKey", null);
__decorate([
  MapToComponentMethod('getFormRef')
], VegaTableEditableController.prototype, "getFormRef", null);
__decorate([
  MapToComponentMethod('getRowData')
], VegaTableEditableController.prototype, "getRowData", null);
