import { __decorate, __param } from '../../../../../../../../external/tslib/tslib.es6.js';
import { coalesce } from '../../../../../base/common/arrays.js';
import { MarkdownString } from '../../../../../base/common/htmlContent.js';
import { Disposable } from '../../../../../base/common/lifecycle.js';
import { basename } from '../../../../../base/common/resources.js';
import { URI } from '../../../../../base/common/uri.js';
import { Range } from '../../../../../editor/common/core/range.js';
import { ITextModelService } from '../../../../../editor/common/services/resolverService.js';
import { localizeWithPath } from '../../../../../nls.js';
import { Action2, registerAction2 } from '../../../../../platform/actions/common/actions.js';
import { ILabelService } from '../../../../../platform/label/common/label.js';
import { ILogService } from '../../../../../platform/log/common/log.js';
import { IQuickInputService } from '../../../../../platform/quickinput/common/quickInput.js';
import { ChatWidget } from '../chatWidget.js';
import { IChatVariablesService } from '../../common/chatVariables.js';
var ChatDynamicVariableModel_1;
const dynamicVariableDecorationType = 'chat-dynamic-variable';
let ChatDynamicVariableModel = class ChatDynamicVariableModel extends Disposable {
    static { ChatDynamicVariableModel_1 = this; }
    static { this.ID = 'chatDynamicVariableModel'; }
    get variables() {
        return [...this._variables];
    }
    get id() {
        return ChatDynamicVariableModel_1.ID;
    }
    constructor(widget, labelService, logService) {
        super();
        this.widget = widget;
        this.labelService = labelService;
        this.logService = logService;
        this._variables = [];
        this._register(widget.inputEditor.onDidChangeModelContent(e => {
            e.changes.forEach(c => {
                this._variables = coalesce(( this._variables.map(ref => {
                    const intersection = Range.intersectRanges(ref.range, c.range);
                    if (intersection && !intersection.isEmpty()) {
                        const rangeToDelete = ( new Range(
                            ref.range.startLineNumber,
                            ref.range.startColumn,
                            ref.range.endLineNumber,
                            ref.range.endColumn - 1
                        ));
                        this.widget.inputEditor.executeEdits(this.id, [{
                                range: rangeToDelete,
                                text: '',
                            }]);
                        return null;
                    }
                    else if (Range.compareRangesUsingStarts(ref.range, c.range) > 0) {
                        const delta = c.text.length - c.rangeLength;
                        return {
                            ...ref,
                            range: {
                                startLineNumber: ref.range.startLineNumber,
                                startColumn: ref.range.startColumn + delta,
                                endLineNumber: ref.range.endLineNumber,
                                endColumn: ref.range.endColumn + delta
                            }
                        };
                    }
                    return ref;
                })));
            });
            this.updateDecorations();
        }));
    }
    getInputState() {
        return this.variables;
    }
    setInputState(s) {
        if (!Array.isArray(s)) {
            this.logService.warn('ChatDynamicVariableModel.setInputState called with invalid state: ' + JSON.stringify(s));
            return;
        }
        this._variables = s;
        this.updateDecorations();
    }
    addReference(ref) {
        this._variables.push(ref);
        this.updateDecorations();
    }
    updateDecorations() {
        this.widget.inputEditor.setDecorationsByType('chat', dynamicVariableDecorationType, ( this._variables.map(r => ({
            range: r.range,
            hoverMessage: this.getHoverForReference(r)
        }))));
    }
    getHoverForReference(ref) {
        const value = ref.data[0];
        if (URI.isUri(value.value)) {
            return ( new MarkdownString(this.labelService.getUriLabel(value.value, { relative: true })));
        }
        else {
            return ( value.value.toString());
        }
    }
};
ChatDynamicVariableModel = ChatDynamicVariableModel_1 = ( __decorate([
    ( __param(1, ILabelService)),
    ( __param(2, ILogService))
], ChatDynamicVariableModel));
ChatWidget.CONTRIBS.push(ChatDynamicVariableModel);
function isSelectAndInsertFileActionContext(context) {
    return 'widget' in context && 'range' in context;
}
class SelectAndInsertFileAction extends Action2 {
    static { this.ID = 'workbench.action.chat.selectAndInsertFile'; }
    constructor() {
        super({
            id: SelectAndInsertFileAction.ID,
            title: ''
        });
    }
    async run(accessor, ...args) {
        const textModelService = accessor.get(ITextModelService);
        const logService = accessor.get(ILogService);
        const quickInputService = accessor.get(IQuickInputService);
        const chatVariablesService = accessor.get(IChatVariablesService);
        const context = args[0];
        if (!isSelectAndInsertFileActionContext(context)) {
            return;
        }
        const doCleanup = () => {
            context.widget.inputEditor.executeEdits('chatInsertFile', [{ range: context.range, text: `` }]);
        };
        let options;
        const filesVariableName = 'files';
        const filesItem = {
            label: ( localizeWithPath(
                'vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables',
                'allFiles',
                'All Files'
            )),
            description: ( localizeWithPath(
                'vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables',
                'allFilesDescription',
                'Search for relevant files in the workspace and provide context from them'
            )),
        };
        if (chatVariablesService.hasVariable(filesVariableName)) {
            options = {
                providerOptions: {
                    additionPicks: [filesItem, { type: 'separator' }]
                },
            };
        }
        const picks = await quickInputService.quickAccess.pick('', options);
        if (!picks?.length) {
            logService.trace('SelectAndInsertFileAction: no file selected');
            doCleanup();
            return;
        }
        const editor = context.widget.inputEditor;
        const range = context.range;
        if (picks[0] === filesItem) {
            const text = `#${filesVariableName}`;
            const success = editor.executeEdits('chatInsertFile', [{ range, text: text + ' ' }]);
            if (!success) {
                logService.trace(`SelectAndInsertFileAction: failed to insert "${text}"`);
                doCleanup();
            }
            return;
        }
        const resource = picks[0].resource;
        if (!textModelService.canHandleResource(resource)) {
            logService.trace('SelectAndInsertFileAction: non-text resource selected');
            doCleanup();
            return;
        }
        const fileName = basename(resource);
        const text = `#file:${fileName}`;
        const success = editor.executeEdits('chatInsertFile', [{ range, text: text + ' ' }]);
        if (!success) {
            logService.trace(`SelectAndInsertFileAction: failed to insert "${text}"`);
            doCleanup();
            return;
        }
        context.widget.getContrib(ChatDynamicVariableModel.ID)?.addReference({
            range: { startLineNumber: range.startLineNumber, startColumn: range.startColumn, endLineNumber: range.endLineNumber, endColumn: range.startColumn + text.length },
            data: [{ level: 'full', value: resource }]
        });
    }
}
registerAction2(SelectAndInsertFileAction);
function isAddDynamicVariableContext(context) {
    return 'widget' in context &&
        'range' in context &&
        'variableData' in context;
}
class AddDynamicVariableAction extends Action2 {
    static { this.ID = 'workbench.action.chat.addDynamicVariable'; }
    constructor() {
        super({
            id: AddDynamicVariableAction.ID,
            title: ''
        });
    }
    async run(accessor, ...args) {
        const context = args[0];
        if (!isAddDynamicVariableContext(context)) {
            return;
        }
        context.widget.getContrib(ChatDynamicVariableModel.ID)?.addReference({
            range: context.range,
            data: context.variableData
        });
    }
}
registerAction2(AddDynamicVariableAction);
export { AddDynamicVariableAction, ChatDynamicVariableModel, SelectAndInsertFileAction, dynamicVariableDecorationType };
