"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MainThreadCommentController = exports.MainThreadCommentThread = exports.MainThreadComments = void 0;
const tslib_1 = require("tslib");
const di_1 = require("@opensumi/di");
const ide_comments_1 = require("@opensumi/ide-comments");
const ide_connection_1 = require("@opensumi/ide-connection");
const next_1 = require("@opensumi/ide-core-browser/lib/menu/next");
const ide_core_common_1 = require("@opensumi/ide-core-common");
const ide_monaco_1 = require("@opensumi/ide-monaco");
const observable_1 = require("@opensumi/ide-monaco/lib/common/observable");
const vscode_1 = require("../../../common/vscode");
const converter_1 = require("../../../common/vscode/converter");
const models_1 = require("../../../common/vscode/models");
let MainThreadComments = class MainThreadComments {
    constructor(rpcProtocol, mainThreadCommands) {
        this.rpcProtocol = rpcProtocol;
        this.mainThreadCommands = mainThreadCommands;
        this._providers = new Map();
        this._commentControllers = new Map();
        this.disposable = new ide_core_common_1.Disposable();
        this.proxy = this.rpcProtocol.getProxy(vscode_1.ExtHostAPIIdentifier.ExtHostComments);
        this.disposable.addDispose(this.registerCommentThreadTemplateHander());
        this.disposable.addDispose(this.registerArgumentProcessor());
    }
    registerCommentThreadTemplateHander() {
        return this.commentsService.onThreadsCreated(async (thread) => {
            // 说明是点击左侧 decoration 创建的，需要在插件进程常见对应的临时评论
            // 插件主动创建的默认有 data
            if ((0, ide_core_common_1.isUndefined)(thread.data)) {
                // 可能当前行的 provider 有很多，参考 vscode 获取第一个
                const providerId = this.commentsService.getProviderIdsByLine(thread.range.startLineNumber)[0];
                if (providerId) {
                    const handle = this._providers.get(providerId);
                    // 说明这个评论是模块创建的
                    if ((0, ide_core_common_1.isUndefined)(handle)) {
                        return;
                    }
                    const commentController = this._commentControllers.get(handle);
                    if (!commentController) {
                        throw new Error('unknown controller');
                    }
                    // 创建一个临时的评论
                    commentController.createCommentThreadTemplate(thread.uri.codeUri, thread.range);
                }
            }
        });
    }
    registerArgumentProcessor() {
        return this.mainThreadCommands.registerArgumentProcessor({
            processArgument: (arg) => {
                if (!arg || !arg.menuId || !arg.thread || (0, ide_core_common_1.isUndefined)(arg.thread.data)) {
                    return arg;
                }
                switch (arg.menuId) {
                    case next_1.MenuId.CommentsCommentThreadTitle:
                        return {
                            $mid: 7,
                            commentControlHandle: arg.thread.data.commentControlHandle,
                            commentThreadHandle: arg.thread.data.commentThreadHandle,
                        };
                    case next_1.MenuId.CommentsCommentThreadContext:
                        return {
                            $mid: 8,
                            thread: {
                                commentControlHandle: arg.thread.data.commentControlHandle,
                                commentThreadHandle: arg.thread.data.commentThreadHandle,
                            },
                            text: arg.text,
                        };
                    case next_1.MenuId.CommentsCommentTitle:
                        return {
                            $mid: 9,
                            thread: {
                                commentControlHandle: arg.thread.data.commentControlHandle,
                                commentThreadHandle: arg.thread.data.commentThreadHandle,
                            },
                            // commentUniqueId 为 number 类型
                            commentUniqueId: +arg.comment.id,
                        };
                    case next_1.MenuId.CommentsCommentContext:
                        return {
                            $mid: 10,
                            thread: {
                                commentControlHandle: arg.thread.data.commentControlHandle,
                                commentThreadHandle: arg.thread.data.commentThreadHandle,
                            },
                            // commentUniqueId 为 number 类型
                            commentUniqueId: +arg.comment.id,
                            text: arg.body,
                        };
                    default:
                        return arg;
                }
            },
        });
    }
    $updateCommentThread(handle, commentThreadHandle, threadId, resource, changes) {
        const provider = this._commentControllers.get(handle);
        if (!provider) {
            return undefined;
        }
        return provider.updateCommentThread(commentThreadHandle, threadId, resource, changes);
    }
    $registerCommentController(handle, id, label) {
        this.commentsService.registerCommentPanel();
        this._providers.set(id, handle);
        const provider = this.injector.get(MainThreadCommentController, [this.proxy, handle, id, label, {}]);
        this._commentControllers.set(handle, provider);
        // 注册后触发 decoration
        this.commentsService.forceUpdateDecoration();
        this.disposable.addDispose(ide_core_common_1.Disposable.create(() => {
            this.$unregisterCommentController(handle);
        }));
    }
    $updateCommentControllerFeatures(handle, features) {
        const provider = this._commentControllers.get(handle);
        if (!provider) {
            return undefined;
        }
        provider.updateFeatures(features);
    }
    $unregisterCommentController(handle) {
        const provider = this._commentControllers.get(handle);
        // 销毁注册的 thread
        if (provider) {
            provider.dispose();
            this._providers.delete(provider.id);
        }
        this._commentControllers.delete(handle);
    }
    $createCommentThread(handle, commentThreadHandle, threadId, resource, range, extensionId) {
        const provider = this._commentControllers.get(handle);
        if (!provider) {
            return undefined;
        }
        return provider.createCommentThread(extensionId, commentThreadHandle, threadId, resource, range);
    }
    $deleteCommentThread(handle, commentThreadHandle) {
        const provider = this._commentControllers.get(handle);
        if (!provider) {
            return;
        }
        return provider.deleteCommentThread(commentThreadHandle);
    }
    dispose() {
        this.disposable.dispose();
        this._commentControllers.clear();
    }
};
exports.MainThreadComments = MainThreadComments;
tslib_1.__decorate([
    (0, di_1.Autowired)(ide_comments_1.ICommentsService),
    tslib_1.__metadata("design:type", Object)
], MainThreadComments.prototype, "commentsService", void 0);
tslib_1.__decorate([
    (0, di_1.Autowired)(di_1.INJECTOR_TOKEN),
    tslib_1.__metadata("design:type", di_1.Injector)
], MainThreadComments.prototype, "injector", void 0);
exports.MainThreadComments = MainThreadComments = tslib_1.__decorate([
    (0, di_1.Injectable)({ multiple: true }),
    tslib_1.__metadata("design:paramtypes", [Object, Object])
], MainThreadComments);
let MainThreadCommentThread = class MainThreadCommentThread extends ide_core_common_1.Disposable {
    get input() {
        return this._input;
    }
    set input(value) {
        this._input = value;
        this._onDidChangeInput.fire(value);
    }
    get onDidChangeInput() {
        return this._onDidChangeInput.event;
    }
    get label() {
        var _a;
        return (_a = this._thread.label) === null || _a === void 0 ? void 0 : _a.get();
    }
    set label(label) {
        (0, observable_1.transaction)((tx) => {
            var _a;
            (_a = this._thread.label) === null || _a === void 0 ? void 0 : _a.set(label, tx);
        });
        this._onDidChangeLabel.fire(label);
    }
    get contextValue() {
        return this._thread.contextValue;
    }
    set contextValue(context) {
        this._thread.contextValue = context;
    }
    convertToIThreadComment(comment) {
        var _a;
        return {
            id: comment.uniqueIdInThread.toString(),
            mode: comment.mode,
            body: typeof comment.body === 'string' ? comment.body : converter_1.MarkdownString.from(comment.body),
            label: comment.label,
            contextValue: comment.contextValue,
            author: {
                name: comment.userName,
                iconPath: new ide_core_common_1.URI(ide_core_common_1.URI.revive(comment.userIconPath)),
            },
            reactions: (_a = comment.commentReactions) === null || _a === void 0 ? void 0 : _a.map((reaction) => this.convertToCommentReaction(reaction)),
            timestamp: comment.timestamp,
        };
    }
    convertToCommentReaction(reaction) {
        const { label, iconPath, count, hasReacted } = reaction;
        return {
            label,
            iconPath: new ide_core_common_1.URI(ide_core_common_1.URI.revive(iconPath)),
            count: count !== null && count !== void 0 ? count : 0,
            authorHasReacted: !!hasReacted,
        };
    }
    convertToCoreReaction(reaction) {
        const { label, iconPath, count, authorHasReacted } = reaction;
        return {
            label,
            iconPath: ide_core_common_1.URI.revive(iconPath),
            count: count !== null && count !== void 0 ? count : 0,
            hasReacted: authorHasReacted,
        };
    }
    convertToCoreComment(comment) {
        var _a;
        return {
            uniqueIdInThread: +comment.id,
            contextValue: comment.contextValue,
            mode: comment.mode,
            label: typeof comment.label === 'string' ? comment.label : '',
            body: comment.body,
            userName: comment.author.name,
            commentReactions: (_a = comment.reactions) === null || _a === void 0 ? void 0 : _a.map((reaction) => this.convertToCoreReaction(reaction)),
            timestamp: comment.timestamp,
        };
    }
    get comments() {
        return this._thread.comments.get().map((comment) => this.convertToCoreComment(comment));
    }
    set comments(newComments) {
        if (newComments) {
            this._thread.updateComments(newComments.map((comment) => this.convertToIThreadComment(comment)));
        }
        else {
            this._thread.updateComments([]);
        }
        this._onDidChangeComments.fire(newComments);
    }
    get onDidChangeComments() {
        return this._onDidChangeComments.event;
    }
    set range(range) {
        this._thread.range = range;
        this._onDidChangeRange.fire(this._thread.range);
    }
    get range() {
        return this._thread.range;
    }
    get onDidChangeCanReply() {
        return this._onDidChangeCanReply.event;
    }
    set canReply(state) {
        this._thread.setReadOnly(!state);
        this._onDidChangeCanReply.fire(state);
    }
    get canReply() {
        return !this._thread.readOnly.get();
    }
    get collapsibleState() {
        return this._thread.isCollapsed.get()
            ? models_1.CommentThreadCollapsibleState.Collapsed
            : models_1.CommentThreadCollapsibleState.Expanded;
    }
    set collapsibleState(newState) {
        (0, observable_1.transaction)((tx) => {
            this._thread.isCollapsed.set(newState === models_1.CommentThreadCollapsibleState.Collapsed, tx);
        });
        this._onDidChangeCollasibleState.fire(this._collapsibleState);
    }
    get isDisposed() {
        return this._isDisposed;
    }
    constructor(commentThreadHandle, controllerHandle, extensionId, threadId, resource, _range, _canReply) {
        super();
        this.commentThreadHandle = commentThreadHandle;
        this.controllerHandle = controllerHandle;
        this.extensionId = extensionId;
        this.threadId = threadId;
        this.resource = resource;
        this._onDidChangeInput = new ide_core_common_1.Emitter();
        this._onDidChangeLabel = new ide_core_common_1.Emitter();
        this.onDidChangeLabel = this._onDidChangeLabel.event;
        this._onDidChangeComments = new ide_core_common_1.Emitter();
        this._onDidChangeCanReply = new ide_core_common_1.Emitter();
        this._onDidChangeRange = new ide_core_common_1.Emitter();
        this.onDidChangeRange = this._onDidChangeRange.event;
        this._onDidChangeCollasibleState = new ide_core_common_1.Emitter();
        this.onDidChangeCollasibleState = this._onDidChangeCollasibleState.event;
        // 查找当前位置 的 threads
        // 框架支持同一个位置多个 thread
        const threads = this.commentsService.commentsThreads.filter((commentThread) => commentThread.uri.toString() === resource && commentThread.range.startLineNumber === _range.startLineNumber);
        // 取最后一个 thread，因为新建的评论在最后一个位置
        const [thread] = threads.slice(-1);
        // 在 data 字段保存 handle id
        const threadData = {
            commentControlHandle: controllerHandle,
            commentThreadHandle,
        };
        // 说明是点击 decoration 新建的 thread
        if (thread && !thread.data) {
            thread.data = threadData;
            this._thread = thread;
        }
        else {
            this._thread = this.commentsService.createThread(new ide_core_common_1.URI(resource), (0, ide_monaco_1.positionToRange)(_range.startLineNumber), {
                data: threadData,
                readOnly: !_canReply,
            });
        }
        this.disposables.push(this.onDidChangeComments(() => {
            this.commentsService.fireThreadCommentChange(this._thread);
        }), this._onDidChangeCollasibleState, this._onDidChangeComments, this._onDidChangeInput, this._onDidChangeLabel, this._onDidChangeRange);
        this._isDisposed = false;
    }
    isDocumentCommentThread() {
        throw new Error('Method not implemented.');
    }
    batchUpdate(changes) {
        const modified = (value) => Object.prototype.hasOwnProperty.call(changes, value);
        if (modified('range')) {
            this.range = changes.range;
        }
        if (modified('label')) {
            this.label = changes.label;
        }
        if (modified('contextValue')) {
            this.contextValue = changes.contextValue;
        }
        if (modified('comments')) {
            this.comments = changes.comments;
        }
        if (modified('collapseState')) {
            this.collapsibleState = changes.collapseState;
        }
        if (modified('canReply')) {
            this.canReply = changes.canReply;
        }
    }
    dispose() {
        this._isDisposed = true;
        this._thread.dispose();
        super.dispose();
    }
    toJSON() {
        return {
            $mid: 7,
            commentControlHandle: this.controllerHandle,
            commentThreadHandle: this.commentThreadHandle,
        };
    }
};
exports.MainThreadCommentThread = MainThreadCommentThread;
tslib_1.__decorate([
    (0, di_1.Autowired)(ide_comments_1.ICommentsService),
    tslib_1.__metadata("design:type", Object)
], MainThreadCommentThread.prototype, "commentsService", void 0);
exports.MainThreadCommentThread = MainThreadCommentThread = tslib_1.__decorate([
    (0, di_1.Injectable)({ multiple: true }),
    tslib_1.__metadata("design:paramtypes", [Number, Number, String, String, String, Object, Boolean])
], MainThreadCommentThread);
let MainThreadCommentController = class MainThreadCommentController extends ide_core_common_1.WithEventBus {
    get handle() {
        return this._handle;
    }
    get id() {
        return this._id;
    }
    get contextValue() {
        return this._id;
    }
    get proxy() {
        return this._proxy;
    }
    get label() {
        return this._label;
    }
    get reactions() {
        return this._reactions;
    }
    set reactions(reactions) {
        this._reactions = reactions;
    }
    get features() {
        return this._features;
    }
    constructor(_proxy, _handle, _id, _label, _features) {
        super();
        this._proxy = _proxy;
        this._handle = _handle;
        this._id = _id;
        this._label = _label;
        this._features = _features;
        this._threads = new Map();
        this.addDispose(this.commentsService.registerCommentRangeProvider(_id, {
            getCommentingRanges: (documentModel) => this.getCommentingRanges(documentModel.uri, ide_core_common_1.CancellationToken.None),
        }));
    }
    updateFeatures(features) {
        var _a;
        this._features = {
            ...this._features,
            ...features,
        };
        this.commentsFeatureRegistry.registerProviderFeature(this._id, {
            placeholder: (_a = this._features.options) === null || _a === void 0 ? void 0 : _a.placeHolder,
        });
    }
    createCommentThread(extensionId, commentThreadHandle, threadId, resource, range) {
        const uri = ide_core_common_1.URI.from(resource);
        const thread = this.injector.get(MainThreadCommentThread, [
            commentThreadHandle,
            this.handle,
            extensionId,
            threadId,
            uri.toString(),
            range,
            true,
        ]);
        this._threads.set(commentThreadHandle, thread);
        this.addDispose({
            dispose: () => {
                this._threads.delete(commentThreadHandle);
                thread.dispose();
            },
        });
        return thread;
    }
    updateCommentThread(commentThreadHandle, _threadId, _resource, changes) {
        const thread = this.getKnownThread(commentThreadHandle);
        thread.batchUpdate(changes);
    }
    deleteCommentThread(commentThreadHandle) {
        const thread = this.getKnownThread(commentThreadHandle);
        this._threads.delete(commentThreadHandle);
        thread.dispose();
    }
    deleteCommentThreadMain(commentThreadId) {
        this._threads.forEach((thread) => {
            if (thread.threadId === commentThreadId) {
                this._proxy.$deleteCommentThread(this._handle, thread.commentThreadHandle);
            }
        });
    }
    getKnownThread(commentThreadHandle) {
        const thread = this._threads.get(commentThreadHandle);
        if (!thread) {
            throw new Error('unknown thread');
        }
        return thread;
    }
    async getCommentingRanges(resource, token) {
        const commentingRanges = await this._proxy.$provideCommentingRanges(this.handle, resource.codeUri, token);
        return commentingRanges || [];
    }
    handleCommentReaction(e) {
        var _a;
        const { thread, comment, reaction } = e.payload;
        const threadHandle = (_a = thread.data) === null || _a === void 0 ? void 0 : _a.commentThreadHandle;
        const mainThread = this.getKnownThread(threadHandle);
        const coreComment = mainThread.convertToCoreComment(comment);
        const coreReaction = mainThread.convertToCoreReaction(reaction);
        this.toggleReaction(thread.uri, mainThread, coreComment, coreReaction);
    }
    async toggleReaction(uri, thread, comment, reaction) {
        return this._proxy.$toggleReaction(this._handle, thread.commentThreadHandle, uri.codeUri, comment, reaction);
    }
    createCommentThreadTemplate(resource, range) {
        this._proxy.$createCommentThreadTemplate(this.handle, resource, range);
    }
    async updateCommentThreadTemplate(threadHandle, range) {
        await this._proxy.$updateCommentThreadTemplate(this.handle, threadHandle, range);
    }
    toJSON() {
        return {
            $mid: 6,
            handle: this.handle,
        };
    }
};
exports.MainThreadCommentController = MainThreadCommentController;
tslib_1.__decorate([
    (0, di_1.Autowired)(di_1.INJECTOR_TOKEN),
    tslib_1.__metadata("design:type", di_1.Injector)
], MainThreadCommentController.prototype, "injector", void 0);
tslib_1.__decorate([
    (0, di_1.Autowired)(ide_comments_1.ICommentsService),
    tslib_1.__metadata("design:type", Object)
], MainThreadCommentController.prototype, "commentsService", void 0);
tslib_1.__decorate([
    (0, di_1.Autowired)(ide_comments_1.ICommentsFeatureRegistry),
    tslib_1.__metadata("design:type", Object)
], MainThreadCommentController.prototype, "commentsFeatureRegistry", void 0);
tslib_1.__decorate([
    (0, ide_core_common_1.OnEvent)(ide_comments_1.CommentReactionClick),
    tslib_1.__metadata("design:type", Function),
    tslib_1.__metadata("design:paramtypes", [ide_comments_1.CommentReactionClick]),
    tslib_1.__metadata("design:returntype", void 0)
], MainThreadCommentController.prototype, "handleCommentReaction", null);
exports.MainThreadCommentController = MainThreadCommentController = tslib_1.__decorate([
    (0, di_1.Injectable)({ multiple: true }),
    tslib_1.__metadata("design:paramtypes", [Object, Number, String, String, Object])
], MainThreadCommentController);
//# sourceMappingURL=main.thread.comments.js.map