import { StateEffect } from '@codemirror/state';
import { keymap } from '@codemirror/view';
import { StateField } from '@codemirror/state';
const DRAFT_ENTRY_INDEX = -1;
const historyInitialState = {
    history: [],
    index: DRAFT_ENTRY_INDEX,
    documentUpdate: null,
    draft: '',
};
const historyState = StateField.define({
    create() {
        return historyInitialState;
    },
    toJSON(value) {
        return JSON.stringify(value);
    },
    update(value, transaction) {
        for (const effect of transaction.effects) {
            if (effect.is(moveInHistory)) {
                if (value.history.length === 0) {
                    return {
                        ...value,
                        documentUpdate: null,
                    };
                }
                const currentHistoryIndex = value.index;
                if (effect.value === 'BACK') {
                    const newHistoryIndex = currentHistoryIndex + 1;
                    if (newHistoryIndex === value.history.length) {
                        return {
                            ...value,
                            documentUpdate: null,
                        };
                    }
                    let draft = value.draft;
                    if (currentHistoryIndex === DRAFT_ENTRY_INDEX) {
                        draft = transaction.state.doc.toString();
                    }
                    return {
                        ...value,
                        draft,
                        index: newHistoryIndex,
                        documentUpdate: value.history[newHistoryIndex],
                    };
                }
                else if (effect.value === 'FORWARDS') {
                    const newHistoryIndex = currentHistoryIndex - 1;
                    if (currentHistoryIndex === DRAFT_ENTRY_INDEX) {
                        return { ...value, documentUpdate: null };
                    }
                    if (newHistoryIndex === DRAFT_ENTRY_INDEX) {
                        return {
                            ...value,
                            index: newHistoryIndex,
                            documentUpdate: value.draft,
                        };
                    }
                    else {
                        return {
                            ...value,
                            index: newHistoryIndex,
                            documentUpdate: value.history[newHistoryIndex],
                        };
                    }
                }
            }
            else if (effect.is(replaceHistory)) {
                return {
                    ...value,
                    index: DRAFT_ENTRY_INDEX,
                    history: effect.value,
                };
            }
        }
        return value;
    },
});
const moveInHistory = StateEffect.define();
export const replaceHistory = StateEffect.define();
function navigateHistory(view, direction) {
    view.dispatch(view.state.update({
        effects: moveInHistory.of(direction),
        selection: { anchor: direction === 'BACK' ? 0 : view.state.doc.length },
    }));
    const updatedHistory = view.state.field(historyState, false);
    if (updatedHistory.documentUpdate !== null) {
        view.dispatch(view.state.update({
            changes: {
                from: 0,
                to: view.state.doc.length,
                insert: updatedHistory.documentUpdate,
            },
        }));
    }
}
export const replMode = ({ history }) => {
    return [
        historyState.init(() => ({
            ...historyInitialState,
            history,
        })),
        keymap.of([
            {
                key: 'ArrowUp',
                preventDefault: true,
                run: (view) => {
                    // If text is selected or cursor is not at top of document, do nothing
                    const { empty, head } = view.state.selection.main;
                    if (!empty || head !== 0) {
                        return false;
                    }
                    navigateHistory(view, 'BACK');
                    return true;
                },
            },
            {
                mac: 'Cmd-ArrowUp',
                win: 'Ctrl-ArrowUp',
                linux: 'Ctrl-ArrowUp',
                preventDefault: true,
                run: (view) => {
                    // If text is selected or cursor is not at top of document, do nothing
                    const { empty, head } = view.state.selection.main;
                    if (!empty || head !== 0) {
                        return false;
                    }
                    navigateHistory(view, 'BACK');
                    return true;
                },
            },
            {
                key: 'ArrowDown',
                preventDefault: true,
                run: (view) => {
                    const { empty, head } = view.state.selection.main;
                    // If text is selected or cursor is not at end of document, do nothing
                    if (!empty || head !== view.state.doc.length) {
                        return false;
                    }
                    navigateHistory(view, 'FORWARDS');
                    return true;
                },
            },
            {
                mac: 'Cmd-ArrowDown',
                win: 'Ctrl-ArrowDown',
                linux: 'Ctrl-ArrowDown',
                preventDefault: true,
                run: (view) => {
                    const { empty, head } = view.state.selection.main;
                    // If text is selected or cursor is not at end of document, do nothing
                    if (!empty || head !== view.state.doc.length) {
                        return false;
                    }
                    navigateHistory(view, 'FORWARDS');
                    return true;
                },
            },
        ]),
    ];
};
//# sourceMappingURL=historyNavigation.js.map