import { RTETableBlock } from '../dto/table-block';
import { InsertChildrenAfterAction } from '../../../dto/actions/insert-children-after-block';
import { getCellSpan, getParentBlockByType, setSpanAttributes, getAllTableRows, getActualColumnPosition, createNewCell, } from '../utils/utils';
import { ActionHandleStrategy } from '../../../dto/action-handle-strategies/action-handle-strategy.abstract';
/**
 * Strategy to handle vertical split of a table cell (splits left/right).
 */
export class SplitCellVerticallyStrategy extends ActionHandleStrategy {
  /**
   * @inheritDoc
   */
  handleAction(_action, target) {
    const row = target.parent;
    const table = getParentBlockByType(row, RTETableBlock);
    const allRows = getAllTableRows(table);
    const currentRowIndex = allRows.indexOf(row);
    const { colSpan, rowSpan } = getCellSpan(target);
    // Get the actual column position of the cell being split
    const cellColumnStart = getActualColumnPosition(target, allRows);
    const cellColumnEnd = cellColumnStart + colSpan - 1;
    // Calculate new column spans (split the column span)
    const leftColSpan = Math.ceil(colSpan / 2);
    const rightColSpan = Math.floor(colSpan / 2);
    // Update original cell's column spans (left cell)
    setSpanAttributes(target, leftColSpan, rowSpan, table);
    // Create new cell (right cell) with same type as original
    const newCell = createNewCell(target.type);
    setSpanAttributes(newCell, rightColSpan, rowSpan, table);
    // Insert new cell after the original in the same row
    row.apply(new InsertChildrenAfterAction(target, newCell));
    // Only when splitting a cell with colSpan=1 do we add a new column to the table.
    // When colSpan>1, we're just redistributing existing columns.
    // For example:
    //   colSpan=1: split into 1+1 → adds 1 new column
    //   colSpan=2: split into 1+1 → just redistributes 2 existing columns
    //   colSpan=3: split into 2+1 → just redistributes 3 existing columns
    const newColumnsAdded = colSpan === 1 ? 1 : 0;
    if (newColumnsAdded > 0) {
      this.updateOtherRowsCells(allRows, currentRowIndex, cellColumnStart, cellColumnEnd, rowSpan, newColumnsAdded, table);
    }
  }
  /**
   * Update cells in other rows to account for the new columns added by the split.
   * When a cell is split vertically and new columns are added to the table,
   * cells in other rows that span across the position where the split happened
   * need their colSpan increased.
   *
   * @param {RTETableRowBlock[]} allRows - All rows in the table.
   * @param {number} splitRowIndex - The index of the row containing the split cell.
   * @param {number} splitColumnStart - The starting column position of the split cell.
   * @param {number} splitColumnEnd - The ending column position of the split cell.
   * @param {number} splitCellRowSpan - The rowSpan of the split cell.
   * @param {number} newColumnsAdded - The number of new columns added by the split.
   * @param {RTETableBlock} table - The table block.
   */
  updateOtherRowsCells(allRows, splitRowIndex, splitColumnStart, splitColumnEnd, splitCellRowSpan, newColumnsAdded, table) {
    // Iterate through all rows
    for (let rowIndex = 0; rowIndex < allRows.length; rowIndex++) {
      const currentRow = allRows[rowIndex];
      // Skip rows that are spanned by the split cell itself
      if (rowIndex >= splitRowIndex && rowIndex < splitRowIndex + splitCellRowSpan) {
        continue;
      }
      // Check each cell in the current row
      for (const cell of currentRow.children) {
        const cellColumnStart = getActualColumnPosition(cell, allRows);
        const { colSpan, rowSpan } = getCellSpan(cell);
        const cellColumnEnd = cellColumnStart + colSpan - 1;
        // Check if this cell spans across the columns where the split happened
        // A cell needs updating if its column range overlaps with the split cell's column range
        const overlaps = cellColumnEnd >= splitColumnStart && cellColumnStart <= splitColumnEnd;
        if (overlaps) {
          // Increase this cell's colSpan by the number of new columns added
          setSpanAttributes(cell, colSpan + newColumnsAdded, rowSpan, table);
          break; // No need to check other cells in this row
        }
      }
    }
  }
}
