"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.backspace = exports.arrowRight = exports.arrowUp = exports.arrowDown = exports.arrowLeft = exports.findFakeParaPosForTextSelection = exports.findFakeParaPosForCodeBlock = exports.findFakeParaPosForNodeSelection = exports.findNextFakeParaPosForGapCursorSelection = void 0;
exports.findFakeParaPosClosestToPos = findFakeParaPosClosestToPos;
exports.createFakeParagraph = createFakeParagraph;
const prosemirror_state_1 = require("prosemirror-state");
const nodes_1 = require("../../../utils/nodes.js");
const selection_1 = require("../../../utils/selection.js");
const GapCursorSelection_1 = require("../Cursor/GapCursorSelection.js");
const isUp = (dir) => dir === 'left' || dir === 'up';
function isTextblock(node) {
    return node.isTextblock && !(0, nodes_1.isCodeBlock)(node);
}
function isEdgeTextblock($cursor, dir) {
    const index = $cursor.index($cursor.depth - 1);
    if (dir === 'before')
        return index === 0;
    if (dir === 'after')
        return index === $cursor.node($cursor.depth - 1).childCount - 1;
    return false;
}
const findNextFakeParaPosForGapCursorSelection = ({ $pos }, dir) => {
    if ($pos.pos !== $pos.start() && $pos.pos !== $pos.end())
        return null;
    return findFakeParaPosClosestToPos($pos, $pos.depth, dir);
};
exports.findNextFakeParaPosForGapCursorSelection = findNextFakeParaPosForGapCursorSelection;
const findFakeParaPosForNodeSelection = (selection, dir) => {
    const selectedNode = selection.node;
    if (selectedNode.isInline || isTextblock(selectedNode))
        return null;
    const { $from } = selection;
    const index = $from.index();
    const parentNode = $from.parent;
    if (dir === 'before') {
        if (parentNode.firstChild === selectedNode || !isTextblock(parentNode.child(index - 1))) {
            return $from;
        }
    }
    else if (dir === 'after') {
        if (parentNode.lastChild === selectedNode || !isTextblock(parentNode.child(index + 1))) {
            return selection.$to;
        }
    }
    return null;
};
exports.findFakeParaPosForNodeSelection = findFakeParaPosForNodeSelection;
const findFakeParaPosForCodeBlock = ($cursor, dir) => {
    if (!(0, nodes_1.isCodeBlock)($cursor.parent))
        return null;
    let foundPos = -1;
    const index = $cursor.index($cursor.depth - 1);
    const parent = $cursor.node($cursor.depth - 1);
    if (dir === 'before') {
        if (index === 0 || !isTextblock(parent.child(index - 1))) {
            foundPos = $cursor.before();
        }
    }
    else if (dir === 'after') {
        if (index === parent.childCount - 1 || !isTextblock(parent.child(index + 1))) {
            foundPos = $cursor.after();
        }
    }
    return foundPos !== -1 ? $cursor.doc.resolve(foundPos) : null;
};
exports.findFakeParaPosForCodeBlock = findFakeParaPosForCodeBlock;
const findFakeParaPosForTextSelection = (selection, dir) => {
    const $cursor = dir === 'before' ? selection.$from : selection.$to;
    if ($cursor.parent.isInline)
        return null;
    const $pos = (0, exports.findFakeParaPosForCodeBlock)($cursor, dir);
    if ($pos)
        return $pos;
    if (!isEdgeTextblock($cursor, dir))
        return null;
    return findFakeParaPosClosestToPos($cursor, $cursor.depth - 1, dir);
};
exports.findFakeParaPosForTextSelection = findFakeParaPosForTextSelection;
function findFakeParaPosClosestToPos($pos, depth, dir) {
    depth++;
    while (--depth > 0) {
        const node = $pos.node(depth);
        const index = $pos.index(depth - 1);
        const parent = $pos.node(depth - 1);
        const isFirstChild = index === 0;
        const isLastChild = index === parent.childCount - 1;
        const isComplexChild = node.type.spec.complex === 'inner' || node.type.spec.complex === 'leaf';
        const disabledGapCursor = parent.type.spec.gapcursor === false;
        if (isComplexChild || disabledGapCursor) {
            if (dir === 'before' && isFirstChild)
                continue;
            if (dir === 'after' && isLastChild)
                continue;
            return null;
        }
        if (dir === 'before') {
            if (isFirstChild || !isTextblock(parent.child(index - 1))) {
                return $pos.doc.resolve($pos.before(depth));
            }
        }
        else if (dir === 'after') {
            if (isLastChild || !isTextblock(parent.child(index + 1))) {
                return $pos.doc.resolve($pos.after(depth));
            }
        }
        return null;
    }
    return null;
}
const arrow = (dir) => (state, dispatch, view) => {
    const { selection } = state;
    const direction = isUp(dir) ? 'before' : 'after';
    let $pos = null;
    if ((0, GapCursorSelection_1.isGapCursorSelection)(selection)) {
        if (selection.meta?.direction !== direction) {
            return false;
        }
        // if gap selection is at start or end of doc
        if (dir === 'up' && selection.pos === 0)
            return true;
        if (dir === 'down' && selection.pos === state.doc.nodeSize - 2)
            return true;
        $pos = (0, exports.findNextFakeParaPosForGapCursorSelection)(selection, direction);
    }
    if ((0, selection_1.isNodeSelection)(selection)) {
        $pos = (0, exports.findFakeParaPosForNodeSelection)(selection, direction);
    }
    if ((0, selection_1.isTextSelection)(selection) && view?.endOfTextblock(dir)) {
        $pos = (0, exports.findFakeParaPosForTextSelection)(selection, direction);
    }
    if ($pos) {
        dispatch?.(createFakeParagraph(state.tr, $pos, direction).scrollIntoView());
        return true;
    }
    return false;
};
function createFakeParagraph(tr, $pos, direction) {
    return tr.setSelection(new GapCursorSelection_1.GapCursorSelection($pos, { meta: { direction } }));
}
exports.arrowLeft = arrow('left');
exports.arrowDown = arrow('down');
exports.arrowUp = arrow('up');
exports.arrowRight = arrow('right');
const backspace = (state, dispatch) => {
    const sel = state.selection;
    if ((0, GapCursorSelection_1.isGapCursorSelection)(sel)) {
        const newSel = prosemirror_state_1.Selection.findFrom(sel.$pos, -1);
        if (newSel) {
            dispatch?.(state.tr.setSelection(newSel).scrollIntoView());
            return true;
        }
    }
    return false;
};
exports.backspace = backspace;
//# sourceMappingURL=commands.js.map
