import type { CellRange, SpreadsheetCommand } from '../types';

export function createFillRangeCommand(
  persistBatch: (
    changes: Array<{ row: number; col: number; value: unknown }>,
  ) => void | Promise<void>,
  before: Array<{ row: number; col: number; value: unknown }>,
  after: Array<{ row: number; col: number; value: unknown }>,
): SpreadsheetCommand {
  return {
    label: 'fillRange',
    undo: () => persistBatch(before),
    redo: () => persistBatch(after),
  };
}

export function normalizeRange(range: CellRange): CellRange {
  return {
    startRow: Math.min(range.startRow, range.endRow),
    startCol: Math.min(range.startCol, range.endCol),
    endRow: Math.max(range.startRow, range.endRow),
    endCol: Math.max(range.startCol, range.endCol),
  };
}

export function iterateRange(
  range: CellRange,
  fn: (row: number, col: number) => void,
) {
  const r = normalizeRange(range);
  for (let row = r.startRow; row <= r.endRow; row += 1) {
    for (let col = r.startCol; col <= r.endCol; col += 1) {
      fn(row, col);
    }
  }
}

export function iterateRanges(
  ranges: CellRange[],
  fn: (row: number, col: number) => void,
) {
  for (const range of ranges) {
    iterateRange(range, fn);
  }
}

export function rangesContainCell(
  ranges: CellRange[],
  row: number,
  col: number,
): boolean {
  for (const range of ranges) {
    const r = normalizeRange(range);
    if (
      row >= r.startRow &&
      row <= r.endRow &&
      col >= r.startCol &&
      col <= r.endCol
    ) {
      return true;
    }
  }
  return false;
}
