import { generateUUID } from '../../../../../utils/misc';
import { InsertChildrenAfterAction } from '../../../dto/actions/insert-children-after-block';
import { InsertChildrenBeforeAction } from '../../../dto/actions/insert-children-before-block';
import { InsertTableRowDirection, } from '../actions/insert-table-row-into-same-section-action';
import { RTETableRowBlock } from '../dto/table-row-block';
import { TableRowCommonUtilitiesStrategy } from './table-row-strategy.abstract';
/**
 * Strategy class for handling the insertion of a new row into a table.
 * The new row will be inserted in the same section (header or body) as the reference row based on the insert direction and the position of the selected rows.
 */
export class InsertTableRowIntoSameSectionStrategy extends TableRowCommonUtilitiesStrategy {
  /**
   * @inheritDoc
   */
  handleAction(action) {
    const { insertDirection, selectedRows } = action;
    // The reference block will control where to insert the new row
    const refBlock = insertDirection === InsertTableRowDirection.ABOVE
      ? selectedRows[0]
      : selectedRows[selectedRows.length - 1];
    const rowBlockJSON = {
      id: generateUUID(),
      type: 'table-row',
      children: [],
    };
    const allRows = refBlock.parent.children;
    const rowCellMaxCount = this.getRowsMaxCellCount(allRows);
    const currentRowIndex = allRows.indexOf(refBlock);
    const rowStartCols = this.getRowCellStartCols(allRows);
    const rowCellMap = new Map();
    for (let i = 0; i < rowCellMaxCount; i++) {
      const { cell, rowIndex } = this.getTheStartSpanCell(allRows, rowStartCols, currentRowIndex, i);
      if (cell) {
        const { colSpan, rowSpan } = cell;
        const shouldIncreaseRowSpan = insertDirection === InsertTableRowDirection.ABOVE
          ? rowIndex !== currentRowIndex
          : rowIndex + rowSpan > currentRowIndex + 1;
        // If the new row is inserted in the middle of the row span, we need to increase the row span of the cell; otherwise, we can just add a new cell.
        if (shouldIncreaseRowSpan) {
          this.updateCellSpan(cell, 'rowspan', rowSpan + 1);
          i += colSpan - 1;
          continue;
        }
        rowCellMap.set(i, this.getDefaultCellBlockTemplate(cell.type, colSpan));
        i += colSpan - 1;
      }
    }
    rowBlockJSON.children = this.getSortedValuesByNumericKey(rowCellMap);
    const newRow = RTETableRowBlock.from(rowBlockJSON);
    const insertAction = insertDirection === InsertTableRowDirection.ABOVE
      ? new InsertChildrenBeforeAction(refBlock, newRow)
      : new InsertChildrenAfterAction(refBlock, newRow);
    refBlock.parent.apply(insertAction);
  }
}
