import { SettingEventHandler, TableSettingType } from './setting-event-handler.abstract';
import { RTETableBlock } from '../dto/table-block';
import { MergeCellsAction } from '../actions/merge-cells-action';
import { getRectangularBounds, getParentBlockByType, getAdjacentCell, } from '../utils/utils';
export var MergeCellsOperationType;
(function (MergeCellsOperationType) {
  MergeCellsOperationType["MERGE_CELLS"] = "MERGE_CELLS";
  MergeCellsOperationType["MERGE_CELL_UP"] = "MERGE_CELL_UP";
  MergeCellsOperationType["MERGE_CELL_RIGHT"] = "MERGE_CELL_RIGHT";
  MergeCellsOperationType["MERGE_CELL_DOWN"] = "MERGE_CELL_DOWN";
  MergeCellsOperationType["MERGE_CELL_LEFT"] = "MERGE_CELL_LEFT";
})(MergeCellsOperationType || (MergeCellsOperationType = {}));
/**
 * Event handler for merge cells operations in a table.
 */
export class MergeCellsOperationEventHandler extends SettingEventHandler {
  /**
   * @inheritDoc
   */
  canHandle(action) {
    return action[0] === TableSettingType.MERGE_CELLS;
  }
  /**
   * @inheritDoc
   */
  execute(action, extensionContext) {
    const selectedCells = extensionContext.tableSelection.getSelectedCells();
    const operation = action[1];
    switch (operation) {
      case MergeCellsOperationType.MERGE_CELL_UP:
      case MergeCellsOperationType.MERGE_CELL_RIGHT:
      case MergeCellsOperationType.MERGE_CELL_DOWN:
      case MergeCellsOperationType.MERGE_CELL_LEFT:
        {
          const mergeCells = this.getDirectionMergeCells(operation, selectedCells[0]);
          this.handleMergeCells(mergeCells, operation);
        }
        break;
      default:
        {
          if (selectedCells.length > 1) {
            this.handleMergeCells(selectedCells, MergeCellsOperationType.MERGE_CELLS);
          }
        }
        break;
    }
  }
  /**
   * Get the adjacent cell in the specified direction.
   *
   * @param {MergeCellsOperationType} direction - The direction to look for the adjacent cell.
   * @param {RTETableCellBlock | RTETableHeadCellBlock} cell - The current cell.
   * @returns {Array<RTETableCellBlock | RTETableHeadCellBlock>} Array containing the cells to merge.
   */
  getDirectionMergeCells(direction, cell) {
    const adjacent = getAdjacentCell(cell, direction);
    if (!adjacent) {
      return [cell];
    }
    switch (direction) {
      case MergeCellsOperationType.MERGE_CELL_UP:
        return [adjacent, cell];
      case MergeCellsOperationType.MERGE_CELL_DOWN:
        return [cell, adjacent];
      case MergeCellsOperationType.MERGE_CELL_LEFT:
        return [adjacent, cell];
      default:
        return [cell, adjacent];
    }
  }
  /**
   * Handle the merge cells operation by creating and applying a MergeCellsAction.
   *
   * @param {Array<RTETableCellBlock | RTETableHeadCellBlock>} mergeCells - The cells to merge.
   * @param {MergeCellsOperationType} direction - The merge cell direction.
   */
  handleMergeCells(mergeCells, direction) {
    if (mergeCells.length < 2) {
      return;
    }
    const rectInfo = getRectangularBounds(mergeCells);
    const { minRow, maxRow, minCol, maxCol, targetCell } = rectInfo;
    const colSpan = maxCol - minCol + 1;
    const rowSpan = maxRow - minRow + 1;
    const action = new MergeCellsAction(targetCell, mergeCells, colSpan, rowSpan, direction);
    this.applyActionOnTable(action, targetCell);
  }
  /**
   * Apply the specified action on the table containing the selected cell.
   *
   * @param {MergeCellsAction} action - The action to apply.
   * @param {RTETableCellBlock | RTETableHeadCellBlock} selectedCell - The selected table cell.
   */
  applyActionOnTable(action, selectedCell) {
    const table = getParentBlockByType(selectedCell, RTETableBlock);
    if (table) {
      table.apply(action);
    }
  }
}
