import { logInvariant } from "./../../../_shared/log-invariant.js";
import { NodeSelection, TextSelection } from "./../../../tiptap/pm/state.js";
import { isInsideList } from "./../../../plugin-commons/index.js";
import { addColumnAfter, addRowAfter, deleteColumn } from "../commands/mutations.js";
import { cellAround, nextCell } from "../commands/queries.js";
import { RicosCellSelection, getRectBetweenCells } from "../plugins/cellselection.js";
import { TableQuery } from "../table-query.js";
import { TableMap } from "../tablemap.js";
import { isRicosCellSelection } from "./is-selection-type.js";
const keyboardShortcuts = {
  Enter: maybeToggleEditMode,
  ArrowLeft: arrow("horiz", -1),
  ArrowRight: arrow("horiz", 1),
  ArrowUp: arrow("vert", -1),
  ArrowDown: arrow("vert", 1),
  "Shift-ArrowLeft": shiftArrow("horiz", -1),
  "Shift-ArrowRight": shiftArrow("horiz", 1),
  "Shift-ArrowUp": shiftArrow("vert", -1),
  "Shift-ArrowDown": shiftArrow("vert", 1),
  Tab: handleTab(1),
  "Shift-Tab": handleTab(-1),
  "Alt-Ctrl-+": ({ editor: { state, view } }) => addColumnAfter(state, view.dispatch),
  "Alt-Ctrl-=": ({ editor: { state, view } }) => addColumnAfter(state, view.dispatch),
  "Alt-Ctrl--": ({ editor: { state, view } }) => deleteColumn(state, view.dispatch),
  "Shift-Space": selectRowRange,
  "Alt-Space": selectColRange,
  Backspace: handleDelete,
  "Mod-Backspace": handleDelete,
  Delete: handleDelete,
  "Mod-Delete": handleDelete
};
function maybeSetSelection(state, dispatch, selection) {
  if (selection.eq(state.selection)) {
    return false;
  }
  if (dispatch) {
    dispatch(state.tr.setSelection(selection).scrollIntoView());
  }
  return true;
}
function arrow(axis, dir) {
  return ({ editor: { state, view } }) => {
    const sel = state.selection;
    if (isRicosCellSelection(sel)) {
      const table = TableQuery.of(sel);
      if (table && table.isTableSelected()) {
        const tableStart = table.getStartPos();
        const tablePos = tableStart - 1;
        if (dir < 0) {
          const nodeSelection = NodeSelection.create(state.doc, tablePos);
          view.dispatch(state.tr.setSelection(nodeSelection));
          return false;
        }
        const afterTablePos = tablePos + table.getNode().nodeSize;
        view.dispatch(
          view.state.tr.setSelection(TextSelection.create(view.state.doc, afterTablePos, afterTablePos)).scrollIntoView()
        );
        return false;
      }
      const $head = nextCell(sel.$headCell, axis, dir);
      if ($head) {
        return maybeSetSelection(state, view.dispatch, new RicosCellSelection([$head], state.doc));
      } else {
        if (!sel.isSingleCell()) {
          return maybeSetSelection(
            state,
            view.dispatch,
            new RicosCellSelection([sel.$headCell], state.doc)
          );
        }
        return true;
      }
    } else {
      const end = atEndOfCell(view, axis, dir);
      if (end === null) {
        return false;
      }
      const $cell = state.doc.resolve(end);
      const $nextCell = nextCell($cell, axis, dir);
      if ($nextCell) {
        const nextCellContentPos = $nextCell.pos + 1;
        const newSelection = TextSelection.near(state.doc.resolve(nextCellContentPos));
        return maybeSetSelection(state, view.dispatch, newSelection);
      }
      return true;
    }
  };
}
function handleTab(dir) {
  return ({ editor: { state, view } }) => {
    if (isInsideList(state)) {
      return false;
    }
    const sel = state.selection;
    const currentCell = cellAround(sel.$head);
    if (!currentCell) {
      return false;
    }
    const $next = nextCell(currentCell, "horiz", dir);
    if ($next) {
      return maybeSetSelection(state, view.dispatch, new RicosCellSelection([$next], state.doc));
    }
    const tableStart = currentCell.start(-1);
    const map = TableMap.get(currentCell.node(-1));
    const cell = map.findCell(currentCell.pos - tableStart);
    if (dir > 0) {
      const nextRow = cell.row + cell.rowspan;
      if (nextRow < map.height) {
        const firstCellPos = map.map[nextRow * map.width];
        const $firstCell = state.doc.resolve(tableStart + firstCellPos);
        return maybeSetSelection(
          state,
          view.dispatch,
          new RicosCellSelection([$firstCell], state.doc)
        );
      }
      addRowAfter(state, (tr) => {
        const newTable = tr.doc.nodeAt(tableStart - 1);
        if (!newTable) {
          logInvariant(new Error(`Table not found at position ${tableStart - 1}`));
          view.dispatch(tr);
          return;
        }
        const newMap = TableMap.get(newTable);
        const newFirstCellPos = newMap.map[(cell.row + cell.rowspan) * newMap.width];
        const $newCell = tr.doc.resolve(tableStart + newFirstCellPos);
        tr.setSelection(new RicosCellSelection([$newCell], tr.doc));
        view.dispatch(tr);
      });
      return true;
    }
    const prevRow = cell.row - 1;
    if (prevRow >= 0) {
      const lastCellPos = map.map[prevRow * map.width + (map.width - 1)];
      const $lastCell = state.doc.resolve(tableStart + lastCellPos);
      return maybeSetSelection(
        state,
        view.dispatch,
        new RicosCellSelection([$lastCell], state.doc)
      );
    }
    return true;
  };
}
function shiftArrow(axis, dir) {
  return ({ editor: { state, view } }) => {
    let sel = state.selection;
    if (!isRicosCellSelection(sel)) {
      const end = atEndOfCell(view, axis, dir);
      if (end === null) {
        return false;
      }
      sel = new RicosCellSelection([state.doc.resolve(end)], state.doc);
    }
    const $head = nextCell(sel.$headCell, axis, dir);
    if (!$head) {
      return true;
    }
    const tableQuery = TableQuery.of(sel);
    if (!tableQuery) {
      return false;
    }
    const rect = getRectBetweenCells([sel.$anchorCell, $head]);
    const cellPositions = tableQuery.map.cellsInRect(rect);
    const cells = cellPositions.map((pos) => state.doc.resolve(tableQuery.getStartPos() + pos));
    const anchorPos = sel.$anchorCell.pos;
    const headPos = $head.pos;
    const reorderedCells = [
      sel.$anchorCell,
      ...cells.filter((c) => c.pos !== anchorPos && c.pos !== headPos),
      $head
    ];
    const selection = new RicosCellSelection(reorderedCells, state.doc);
    return maybeSetSelection(state, view.dispatch, selection);
  };
}
function maybeToggleEditMode({ editor }) {
  const sel = editor.state.selection;
  if (isRicosCellSelection(sel)) {
    const table = TableQuery.of(sel);
    if (table && table.isTableSelected()) {
      const map = table.getMap();
      const firstCellPos = table.getStartPos() + map[0];
      const $firstCell = editor.state.doc.resolve(firstCellPos);
      const cellSelection = new RicosCellSelection([$firstCell], editor.state.doc);
      editor.view.dispatch(editor.state.tr.setSelection(cellSelection));
      return true;
    }
    if (sel.ranges.length === 1) {
      editor.commands.setEditCell();
    }
    return true;
  }
  return false;
}
function selectRowRange({ editor }) {
  if (isRicosCellSelection(editor.state.selection)) {
    const { selection } = editor.state;
    const table = selection.$anchorCell.node(-1);
    const tableStart = selection.$anchorCell.start(-1);
    const map = TableMap.get(table);
    const anchorRow = map.findCell(selection.$anchorCell.pos - tableStart).row;
    const headRow = map.findCell(selection.$headCell.pos - tableStart).row;
    const fromRow = Math.min(anchorRow, headRow);
    const toRow = Math.max(anchorRow, headRow);
    const rect = { left: 0, right: map.width, top: fromRow, bottom: toRow + 1 };
    const cellPositions = map.cellsInRect(rect);
    const cells = cellPositions.map((pos) => editor.state.doc.resolve(tableStart + pos));
    const newSelection = new RicosCellSelection(cells, editor.state.doc);
    editor.view.dispatch(editor.state.tr.setSelection(newSelection));
    return true;
  }
  return false;
}
function selectColRange({ editor }) {
  if (isRicosCellSelection(editor.state.selection)) {
    const { selection } = editor.state;
    const table = selection.$anchorCell.node(-1);
    const tableStart = selection.$anchorCell.start(-1);
    const map = TableMap.get(table);
    const anchorCol = map.findCell(selection.$anchorCell.pos - tableStart).col;
    const headCol = map.findCell(selection.$headCell.pos - tableStart).col;
    const fromCol = Math.min(anchorCol, headCol);
    const toCol = Math.max(anchorCol, headCol);
    const rect = { left: fromCol, right: toCol + 1, top: 0, bottom: map.height };
    const cellPositions = map.cellsInRect(rect);
    const cells = cellPositions.map((pos) => editor.state.doc.resolve(tableStart + pos));
    const newSelection = new RicosCellSelection(cells, editor.state.doc);
    editor.view.dispatch(editor.state.tr.setSelection(newSelection));
    return true;
  }
  return false;
}
function atEndOfCell(view, axis, dir) {
  if (!(view.state.selection instanceof TextSelection)) {
    return null;
  }
  const { $head } = view.state.selection;
  for (let d = $head.depth - 1; d >= 0; d--) {
    const parent = $head.node(d), index = dir < 0 ? $head.index(d) : $head.indexAfter(d);
    if (index !== (dir < 0 ? 0 : parent.childCount)) {
      return null;
    }
    if (parent.type.spec.tableRole === "cell" || parent.type.spec.tableRole === "header_cell") {
      const cellPos = $head.before(d);
      const dirStr = axis === "vert" ? dir > 0 ? "down" : "up" : dir > 0 ? "right" : "left";
      return view.endOfTextblock(dirStr) ? cellPos : null;
    }
  }
  return null;
}
function handleDelete({ editor }) {
  const { selection, tr } = editor.state;
  const tableQuery = TableQuery.of(selection);
  if (!tableQuery) {
    return false;
  }
  if (selection.from < tableQuery.getStartPos() || selection.to >= tableQuery.getStartPos() + tableQuery.getNode().nodeSize) {
    const effectiveFrom = Math.min(selection.from, tableQuery.table.pos);
    const effectiveTo = Math.max(
      selection.to,
      tableQuery.table.pos + tableQuery.table.node.nodeSize
    );
    tr.delete(effectiveFrom, effectiveTo);
    editor.view.dispatch(tr);
    return true;
  }
  if (!(selection instanceof RicosCellSelection)) {
    return false;
  }
  const cleared = editor.commands.clearCell();
  if (cleared) {
    return true;
  }
  if (selection.isColSelection() && selection.isRowSelection()) {
    editor.commands.deleteTable();
    return true;
  }
  if (selection.isColSelection()) {
    editor.commands.deleteColumn();
    return true;
  }
  if (selection.isRowSelection()) {
    editor.commands.deleteRow();
    return true;
  }
  return false;
}
export {
  keyboardShortcuts,
  maybeToggleEditMode
};
//# sourceMappingURL=keyboard-shortcuts.js.map
