/**
 * Wraps the current selection in CodeMirror with the given prefix and suffix.
 */
export function wrapSelection(
    view: any,
    prefix: string,
    suffix: string = prefix
) {
    if (!view || view.updateInProgress) return;

    const { state } = view;
    view.dispatch(
        state.changeByRange((range: any) => {
            return {
                changes: [
                    { from: range.from, insert: prefix },
                    { from: range.to, insert: suffix }
                ],
                range: range.constructor.range(
                    range.from + prefix.length,
                    range.to + prefix.length
                )
            };
        })
    );
    view.focus();
}

/**
 * Inserts a prefix at the start of each line in the selection (e.g., for lists or blockquotes).
 */
export function toggleLinePrefix(view: any, prefix: string) {
    if (!view || view.updateInProgress) return;

    const { state } = view;
    view.dispatch(
        state.changeByRange((range: any) => {
            const lines = [];
            for (let pos = range.from; pos <= range.to; ) {
                const line = state.doc.lineAt(pos);
                lines.push(line);
                pos = line.to + 1;
            }

            const isAlreadyPrefixed = lines.every((l) =>
                l.text.startsWith(prefix)
            );
            const lineChanges = lines.map((l) => {
                if (isAlreadyPrefixed) {
                    return {
                        from: l.from,
                        to: l.from + prefix.length,
                        insert: ''
                    };
                } else {
                    return { from: l.from, insert: prefix };
                }
            });

            const newFrom =
                range.from +
                (isAlreadyPrefixed ? -prefix.length : prefix.length);
            const newTo =
                range.to +
                (isAlreadyPrefixed
                    ? -prefix.length * lines.length
                    : prefix.length * lines.length);

            return {
                changes: lineChanges,
                range: range.constructor.range(
                    newFrom,
                    Math.max(newFrom, newTo)
                )
            };
        })
    );
    view.focus();
}
