
import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
import { Color } from '../../../../base/common/color.js';
import { Emitter } from '../../../../base/common/event.js';
import { DisposableStore } from '../../../../base/common/lifecycle.js';
import { MouseTargetType, isCodeEditor } from '../../../../editor/browser/editorBrowser.js';
import { Range } from '../../../../editor/common/core/range.js';
import { CommentState, CommentThreadCollapsibleState } from '../../../../editor/common/languages.js';
import { ZoneWidget } from '../../../../editor/contrib/zoneWidget/browser/zoneWidget.js';
import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.service.js';
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
import { IThemeService } from '../../../../platform/theme/common/themeService.service.js';
import { CommentGlyphWidget } from './commentGlyphWidget.js';
import { ICommentService } from './commentService.service.js';
import { EditorOption } from '../../../../editor/common/config/editorOptions.js';
import { ServiceCollection } from '../../../../platform/instantiation/common/serviceCollection.js';
import { CommentThreadWidget } from './commentThreadWidget.js';
import { getCommentThreadStateBorderColor, commentThreadStateColorVar, commentThreadStateBackgroundColorVar } from './commentColors.js';
import { peekViewBorder } from '../../../../editor/contrib/peekView/browser/peekView.js';
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.service.js';
import { StableEditorScrollState } from '../../../../editor/browser/stableEditorScroll.js';
import Severity$1 from '../../../../base/common/severity.js';
import { localize } from '../../../../nls.js';
import { IDialogService } from '../../../../platform/dialogs/common/dialogs.service.js';

function getCommentThreadWidgetStateColor(thread, theme) {
    return getCommentThreadStateBorderColor(thread, theme) ?? theme.getColor(peekViewBorder);
}
function commentThreadHasDraft(commentThread) {
    const comments = commentThread.comments;
    if (!comments) {
        return false;
    }
    return ( comments.some(comment => comment.state === CommentState.Draft));
}
var CommentWidgetFocus;
(function(CommentWidgetFocus) {
    CommentWidgetFocus[CommentWidgetFocus["None"] = 0] = "None";
    CommentWidgetFocus[CommentWidgetFocus["Widget"] = 1] = "Widget";
    CommentWidgetFocus[CommentWidgetFocus["Editor"] = 2] = "Editor";
})(CommentWidgetFocus || (CommentWidgetFocus = {}));
function parseMouseDownInfoFromEvent(e) {
    const range = e.target.range;
    if (!range) {
        return null;
    }
    if (!e.event.leftButton) {
        return null;
    }
    if (e.target.type !== MouseTargetType.GUTTER_LINE_DECORATIONS) {
        return null;
    }
    const data = e.target.detail;
    const gutterOffsetX = data.offsetX - data.glyphMarginWidth - data.lineNumbersWidth - data.glyphMarginLeft;
    if (gutterOffsetX > 20) {
        return null;
    }
    return {
        lineNumber: range.startLineNumber
    };
}
function isMouseUpEventDragFromMouseDown(mouseDownInfo, e) {
    if (!mouseDownInfo) {
        return null;
    }
    const {
        lineNumber
    } = mouseDownInfo;
    const range = e.target.range;
    if (!range) {
        return null;
    }
    return lineNumber;
}
let ReviewZoneWidget = class ReviewZoneWidget extends ZoneWidget {
    get uniqueOwner() {
        return this._uniqueOwner;
    }
    get commentThread() {
        return this._commentThread;
    }
    get expanded() {
        return this._isExpanded;
    }
    constructor(
        editor,
        _uniqueOwner,
        _commentThread,
        _pendingComment,
        _pendingEdits,
        instantiationService,
        themeService,
        commentService,
        contextKeyService,
        configurationService,
        dialogService
    ) {
        super(editor, {
            keepEditorSelection: true,
            isAccessible: true,
            showArrow: !!_commentThread.range
        });
        this._uniqueOwner = _uniqueOwner;
        this._commentThread = _commentThread;
        this._pendingComment = _pendingComment;
        this._pendingEdits = _pendingEdits;
        this.themeService = themeService;
        this.commentService = commentService;
        this.configurationService = configurationService;
        this.dialogService = dialogService;
        this._onDidClose = ( new Emitter());
        this._onDidCreateThread = ( new Emitter());
        this._onDidChangeExpandedState = ( new Emitter());
        this._globalToDispose = ( new DisposableStore());
        this._commentThreadDisposables = [];
        this._contextKeyService = this._globalToDispose.add(contextKeyService.createScoped(this.domNode));
        this._scopedInstantiationService = this._globalToDispose.add(instantiationService.createChild(( new ServiceCollection([IContextKeyService, this._contextKeyService]))));
        const controller = this.commentService.getCommentController(this._uniqueOwner);
        if (controller) {
            this._commentOptions = controller.options;
        }
        this._initialCollapsibleState = _pendingComment ? CommentThreadCollapsibleState.Expanded : _commentThread.initialCollapsibleState;
        _commentThread.initialCollapsibleState = this._initialCollapsibleState;
        this._commentThreadDisposables = [];
        this.create();
        this._globalToDispose.add(this.themeService.onDidColorThemeChange(this._applyTheme, this));
        this._globalToDispose.add(this.editor.onDidChangeConfiguration(e => {
            if (e.hasChanged(EditorOption.fontInfo)) {
                this._applyTheme();
            }
        }));
        this._applyTheme();
    }
    get onDidClose() {
        return this._onDidClose.event;
    }
    get onDidCreateThread() {
        return this._onDidCreateThread.event;
    }
    get onDidChangeExpandedState() {
        return this._onDidChangeExpandedState.event;
    }
    getPosition() {
        if (this.position) {
            return this.position;
        }
        if (this._commentGlyph) {
            return this._commentGlyph.getPosition().position ?? undefined;
        }
        return undefined;
    }
    revealRange() {}
    reveal(commentUniqueId, focus = CommentWidgetFocus.None) {
        this.makeVisible(commentUniqueId, focus);
        const comment = this._commentThread.comments?.find(comment => comment.uniqueIdInThread === commentUniqueId) ?? this._commentThread.comments?.[0];
        this.commentService.setActiveCommentAndThread(this.uniqueOwner, {
            thread: this._commentThread,
            comment
        });
    }
    _expandAndShowZoneWidget() {
        if (!this._isExpanded) {
            this.show(this.arrowPosition(this._commentThread.range), 2);
        }
    }
    _setFocus(commentUniqueId, focus) {
        if (focus === CommentWidgetFocus.Widget) {
            this._commentThreadWidget.focus(commentUniqueId);
        } else if (focus === CommentWidgetFocus.Editor) {
            this._commentThreadWidget.focusCommentEditor();
        }
    }
    _goToComment(commentUniqueId, focus) {
        const height = this.editor.getLayoutInfo().height;
        const coords = this._commentThreadWidget.getCommentCoords(commentUniqueId);
        if (coords) {
            let scrollTop = 1;
            if (this._commentThread.range) {
                const commentThreadCoords = coords.thread;
                const commentCoords = coords.comment;
                scrollTop = this.editor.getTopForLineNumber(this._commentThread.range.startLineNumber) - height / 2 + commentCoords.top - commentThreadCoords.top;
            }
            this.editor.setScrollTop(scrollTop);
            this._setFocus(commentUniqueId, focus);
        } else {
            this._goToThread(focus);
        }
    }
    _goToThread(focus) {
        const rangeToReveal = this._commentThread.range ? ( new Range(
            this._commentThread.range.startLineNumber,
            this._commentThread.range.startColumn,
            this._commentThread.range.endLineNumber + 1,
            1
        )) : ( new Range(1, 1, 1, 1));
        this.editor.revealRangeInCenter(rangeToReveal);
        this._setFocus(undefined, focus);
    }
    makeVisible(commentUniqueId, focus = CommentWidgetFocus.None) {
        this._expandAndShowZoneWidget();
        if (commentUniqueId !== undefined) {
            this._goToComment(commentUniqueId, focus);
        } else {
            this._goToThread(focus);
        }
    }
    getPendingComments() {
        return {
            newComment: this._commentThreadWidget.getPendingComment(),
            edits: this._commentThreadWidget.getPendingEdits()
        };
    }
    setPendingComment(pending) {
        this._pendingComment = pending;
        this.expand();
        this._commentThreadWidget.setPendingComment(pending);
    }
    _fillContainer(container) {
        this.setCssClass("review-widget");
        this._commentThreadWidget = this._scopedInstantiationService.createInstance(
            CommentThreadWidget,
            container,
            this.editor,
            this._uniqueOwner,
            this.editor.getModel().uri,
            this._contextKeyService,
            this._scopedInstantiationService,
            this._commentThread,
            this._pendingComment,
            this._pendingEdits,
            {
                context: this.editor
            },
            this._commentOptions,
            {
                actionRunner: async () => {
                    if (!this._commentThread.comments || !this._commentThread.comments.length) {
                        const newPosition = this.getPosition();
                        if (newPosition) {
                            const originalRange = this._commentThread.range;
                            if (!originalRange) {
                                return;
                            }
                            let range;
                            if (newPosition.lineNumber !== originalRange.endLineNumber) {
                                const distance = newPosition.lineNumber - originalRange.endLineNumber;
                                range = ( new Range(
                                    originalRange.startLineNumber + distance,
                                    originalRange.startColumn,
                                    originalRange.endLineNumber + distance,
                                    originalRange.endColumn
                                ));
                            } else {
                                range = ( new Range(
                                    originalRange.startLineNumber,
                                    originalRange.startColumn,
                                    originalRange.endLineNumber,
                                    originalRange.endColumn
                                ));
                            }
                            await this.commentService.updateCommentThreadTemplate(this.uniqueOwner, this._commentThread.commentThreadHandle, range);
                        }
                    }
                },
                collapse: () => {
                    return this.collapse(true);
                }
            }
        );
        this._disposables.add(this._commentThreadWidget);
    }
    arrowPosition(range) {
        if (!range) {
            return undefined;
        }
        return {
            lineNumber: range.endLineNumber,
            column: range.endLineNumber === range.startLineNumber ? (range.startColumn + range.endColumn + 1) / 2 : 1
        };
    }
    deleteCommentThread() {
        this.dispose();
        this.commentService.disposeCommentThread(this.uniqueOwner, this._commentThread.threadId);
    }
    doCollapse() {
        this._commentThread.collapsibleState = CommentThreadCollapsibleState.Collapsed;
    }
    async collapse(confirm = false) {
        if (!confirm || (await this.confirmCollapse())) {
            this.doCollapse();
            return true;
        } else {
            return false;
        }
    }
    async confirmCollapse() {
        const confirmSetting = this.configurationService.getValue("comments.thread.confirmOnCollapse");
        if (confirmSetting === "whenHasUnsubmittedComments" && this._commentThreadWidget.hasUnsubmittedComments) {
            const result = await this.dialogService.confirm({
                message: ( localize(
                    7833,
                    "Collapsing this comment thread will discard unsubmitted comments. Are you sure you want to discard these comments?"
                )),
                primaryButton: ( localize(7834, "Discard")),
                type: Severity$1.Warning,
                checkbox: {
                    label: ( localize(7835, "Never ask me again")),
                    checked: false
                }
            });
            if (result.checkboxChecked) {
                await this.configurationService.updateValue("comments.thread.confirmOnCollapse", "never");
            }
            return result.confirmed;
        }
        return true;
    }
    expand(setActive) {
        this._commentThread.collapsibleState = CommentThreadCollapsibleState.Expanded;
        if (setActive) {
            this.commentService.setActiveCommentAndThread(this.uniqueOwner, {
                thread: this._commentThread
            });
        }
    }
    getGlyphPosition() {
        if (this._commentGlyph) {
            return this._commentGlyph.getPosition().position.lineNumber;
        }
        return 0;
    }
    async update(commentThread) {
        if (this._commentThread !== commentThread) {
            this._commentThreadDisposables.forEach(disposable => disposable.dispose());
            this._commentThread = commentThread;
            this._commentThreadDisposables = [];
            this.bindCommentThreadListeners();
        }
        await this._commentThreadWidget.updateCommentThread(commentThread);
        const lineNumber = this._commentThread.range?.endLineNumber ?? 1;
        let shouldMoveWidget = false;
        if (this._commentGlyph) {
            const hasDraft = commentThreadHasDraft(commentThread);
            this._commentGlyph.setThreadState(commentThread.state, hasDraft);
            if (this._commentGlyph.getPosition().position.lineNumber !== lineNumber) {
                shouldMoveWidget = true;
                this._commentGlyph.setLineNumber(lineNumber);
            }
        }
        if ((shouldMoveWidget && this._isExpanded) || (this._commentThread.collapsibleState === CommentThreadCollapsibleState.Expanded && !this._isExpanded)) {
            this.show(this.arrowPosition(this._commentThread.range), 2);
        } else if (this._commentThread.collapsibleState !== CommentThreadCollapsibleState.Expanded) {
            this.hide();
        }
    }
    _onWidth(widthInPixel) {
        this._commentThreadWidget.layout(widthInPixel);
    }
    _doLayout(heightInPixel, widthInPixel) {
        this._commentThreadWidget.layout(widthInPixel);
    }
    async display(range, shouldReveal) {
        if (range) {
            this._commentGlyph = ( new CommentGlyphWidget(this.editor, range?.endLineNumber ?? -1));
            const hasDraft = commentThreadHasDraft(this._commentThread);
            this._commentGlyph.setThreadState(this._commentThread.state, hasDraft);
            this._globalToDispose.add(this._commentGlyph.onDidChangeLineNumber(async e => {
                if (!this._commentThread.range) {
                    return;
                }
                const shift = e - (this._commentThread.range.endLineNumber);
                const newRange = ( new Range(
                    this._commentThread.range.startLineNumber + shift,
                    this._commentThread.range.startColumn,
                    this._commentThread.range.endLineNumber + shift,
                    this._commentThread.range.endColumn
                ));
                this._commentThread.range = newRange;
            }));
        }
        await this._commentThreadWidget.display(this.editor.getOption(EditorOption.lineHeight), shouldReveal);
        this._disposables.add(this._commentThreadWidget.onDidResize(dimension => {
            this._refresh(dimension);
        }));
        if (this._commentThread.collapsibleState === CommentThreadCollapsibleState.Expanded) {
            this.show(this.arrowPosition(range), 2);
        }
        if (shouldReveal) {
            this.makeVisible();
        }
        this.bindCommentThreadListeners();
    }
    bindCommentThreadListeners() {
        this._commentThreadDisposables.push(this._commentThread.onDidChangeComments(async _ => {
            await this.update(this._commentThread);
        }));
        this._commentThreadDisposables.push(this._commentThread.onDidChangeCollapsibleState(state => {
            if (state === CommentThreadCollapsibleState.Expanded && !this._isExpanded) {
                this.show(this.arrowPosition(this._commentThread.range), 2);
                this._commentThreadWidget.ensureFocusIntoNewEditingComment();
                return;
            }
            if (state === CommentThreadCollapsibleState.Collapsed && this._isExpanded) {
                this.hide();
                return;
            }
        }));
        if (this._initialCollapsibleState === undefined) {
            const onDidChangeInitialCollapsibleState = this._commentThread.onDidChangeInitialCollapsibleState(state => {
                this._initialCollapsibleState = state;
                this._commentThread.collapsibleState = this._initialCollapsibleState;
                onDidChangeInitialCollapsibleState.dispose();
            });
            this._commentThreadDisposables.push(onDidChangeInitialCollapsibleState);
        }
        this._commentThreadDisposables.push(this._commentThread.onDidChangeState(() => {
            const borderColor = getCommentThreadWidgetStateColor(this._commentThread.state, this.themeService.getColorTheme()) || Color.transparent;
            this.style({
                frameColor: borderColor,
                arrowColor: borderColor
            });
            this.container?.style.setProperty(commentThreadStateColorVar, `${borderColor}`);
            this.container?.style.setProperty(commentThreadStateBackgroundColorVar, `${( borderColor.transparent(.1))}`);
        }));
    }
    async submitComment() {
        return this._commentThreadWidget.submitComment();
    }
    _refresh(dimensions) {
        if ((this._isExpanded === undefined) && (dimensions.height === 0) && (dimensions.width === 0)) {
            this.commentThread.collapsibleState = CommentThreadCollapsibleState.Collapsed;
            return;
        }
        if (this._isExpanded) {
            this._commentThreadWidget.layout();
            const headHeight = Math.ceil(this.editor.getOption(EditorOption.lineHeight) * 1.2);
            const lineHeight = this.editor.getOption(EditorOption.lineHeight);
            const arrowHeight = Math.round(lineHeight / 3);
            const frameThickness = Math.round(lineHeight / 9) * 2;
            const computedLinesNumber = Math.ceil(
                (headHeight + dimensions.height + arrowHeight + frameThickness + 8)  / lineHeight
            );
            if (this._viewZone?.heightInLines === computedLinesNumber) {
                return;
            }
            const currentPosition = this.getPosition();
            if (this._viewZone && currentPosition && currentPosition.lineNumber !== this._viewZone.afterLineNumber && this._viewZone.afterLineNumber !== 0) {
                this._viewZone.afterLineNumber = currentPosition.lineNumber;
            }
            const capture = StableEditorScrollState.capture(this.editor);
            this._relayout(computedLinesNumber);
            capture.restore(this.editor);
        }
    }
    _applyTheme() {
        const borderColor = getCommentThreadWidgetStateColor(this._commentThread.state, this.themeService.getColorTheme()) || Color.transparent;
        this.style({
            arrowColor: borderColor,
            frameColor: borderColor
        });
        const fontInfo = this.editor.getOption(EditorOption.fontInfo);
        this._commentThreadWidget.applyTheme(fontInfo);
    }
    show(rangeOrPos, heightInLines) {
        const glyphPosition = this._commentGlyph?.getPosition();
        let range = Range.isIRange(rangeOrPos) ? rangeOrPos : (rangeOrPos ? Range.fromPositions(rangeOrPos) : undefined);
        if (glyphPosition?.position && range && glyphPosition.position.lineNumber !== range.endLineNumber) {
            const distance = glyphPosition.position.lineNumber - range.endLineNumber;
            range = ( new Range(
                range.startLineNumber + distance,
                range.startColumn,
                range.endLineNumber + distance,
                range.endColumn
            ));
        }
        const wasExpanded = this._isExpanded;
        this._isExpanded = true;
        super.show(range ?? ( new Range(0, 0, 0, 0)), heightInLines);
        this._commentThread.collapsibleState = CommentThreadCollapsibleState.Expanded;
        this._refresh(this._commentThreadWidget.getDimensions());
        if (!wasExpanded) {
            this._onDidChangeExpandedState.fire(true);
        }
    }
    async collapseAndFocusRange() {
        if ((await this.collapse(true)) && Range.isIRange(this.commentThread.range) && isCodeEditor(this.editor)) {
            this.editor.setSelection(this.commentThread.range);
        }
    }
    hide() {
        if (this._isExpanded) {
            this._isExpanded = false;
            if (this.editor.hasWidgetFocus()) {
                this.editor.focus();
            }
            if (!this._commentThread.comments || !this._commentThread.comments.length) {
                this.deleteCommentThread();
            }
            this._onDidChangeExpandedState.fire(false);
        }
        super.hide();
    }
    dispose() {
        super.dispose();
        if (this._commentGlyph) {
            this._commentGlyph.dispose();
            this._commentGlyph = undefined;
        }
        this._globalToDispose.dispose();
        this._commentThreadDisposables.forEach(global => global.dispose());
        this._onDidClose.fire(undefined);
        this._onDidClose.dispose();
        this._onDidCreateThread.dispose();
        this._onDidChangeExpandedState.dispose();
    }
};
ReviewZoneWidget = ( __decorate([( __param(5, IInstantiationService)), ( __param(6, IThemeService)), ( __param(7, ICommentService)), ( __param(8, IContextKeyService)), ( __param(9, IConfigurationService)), ( __param(10, IDialogService))], ReviewZoneWidget));

export { CommentWidgetFocus, ReviewZoneWidget, isMouseUpEventDragFromMouseDown, parseMouseDownInfoFromEvent };
