import { EditOperation } from '../../../../editor/common/core/editOperation.js';
import { LineRange } from '../../../../editor/common/core/lineRange.js';
import { Range } from '../../../../editor/common/core/range.js';
import { AsyncIterableSource } from '../../../../base/common/async.js';
import { getNWords } from '../../chat/common/chatWordCounter.js';
function invertLineRange(range, model) {
    if (range.isEmpty) {
        return [];
    }
    const result = [];
    if (range.startLineNumber > 1) {
        result.push(( new LineRange(1, range.startLineNumber)));
    }
    if (range.endLineNumberExclusive < model.getLineCount() + 1) {
        result.push(( new LineRange(range.endLineNumberExclusive, model.getLineCount() + 1)));
    }
    return result.filter(r => !r.isEmpty);
}
function asRange(lineRange, model) {
    return lineRange.isEmpty
        ? ( new Range(
        lineRange.startLineNumber,
        1,
        lineRange.startLineNumber,
        model.getLineLength(lineRange.startLineNumber)
    ))
        : ( new Range(
        lineRange.startLineNumber,
        1,
        lineRange.endLineNumberExclusive - 1,
        model.getLineLength(lineRange.endLineNumberExclusive - 1)
    ));
}
async function performAsyncTextEdit(model, edit, progress, obs) {
    const [id] = model.deltaDecorations([], [{
            range: edit.range,
            options: {
                description: 'asyncTextEdit',
                stickiness: 0
            }
        }]);
    let first = true;
    for await (const part of edit.newText) {
        if (model.isDisposed()) {
            break;
        }
        const range = model.getDecorationRange(id);
        if (!range) {
            throw ( new Error(
                'FAILED to perform async replace edit because the anchor decoration was removed'
            ));
        }
        const edit = first
            ? EditOperation.replace(range, part)
            : EditOperation.insert(range.getEndPosition(), part);
        obs?.start();
        model.pushEditOperations(null, [edit], (undoEdits) => {
            progress?.report(undoEdits);
            return null;
        });
        obs?.stop();
        first = false;
    }
}
function asProgressiveEdit(interval, edit, wordsPerSec, token) {
    wordsPerSec = Math.max(30, wordsPerSec);
    const stream = ( new AsyncIterableSource());
    let newText = edit.text ?? '';
    interval.cancelAndSet(() => {
        const r = getNWords(newText, 1);
        stream.emitOne(r.value);
        newText = newText.substring(r.value.length);
        if (r.isFullString) {
            interval.cancel();
            stream.resolve();
            d.dispose();
        }
    }, 1000 / wordsPerSec);
    const d = token.onCancellationRequested(() => {
        interval.cancel();
        stream.resolve();
        d.dispose();
    });
    return {
        range: edit.range,
        newText: stream.asyncIterable
    };
}
export { asProgressiveEdit, asRange, invertLineRange, performAsyncTextEdit };
