import { createCancelablePromise, timeout } from "../../../../base/common/async.mjs";
import { onUnexpectedError } from "../../../../base/common/errors.mjs";
import { EditorState } from "../../editorState/browser/editorState.mjs";
import { registerEditorContribution, registerEditorAction, EditorAction } from "../../../browser/editorExtensions.mjs";
import { Range } from "../../../common/core/range.mjs";
import { Selection } from "../../../common/core/selection.mjs";
import { EditorContextKeys } from "../../../common/editorContextKeys.mjs";
import { ModelDecorationOptions } from "../../../common/model/textModel.mjs";
import { IEditorWorkerService } from "../../../common/services/editorWorker.mjs";
import { editorBracketMatchBorder } from "../../../common/core/editorColorRegistry.mjs";
import { localize } from "../../../../nls.mjs";
import { registerThemingParticipant } from "../../../../platform/theme/common/themeService.mjs";
import { InPlaceReplaceCommand } from "./inPlaceReplaceCommand.mjs";
var __decorate = globalThis && globalThis.__decorate || function(decorators, target, key, desc) {
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
    r = Reflect.decorate(decorators, target, key, desc);
  else
    for (var i = decorators.length - 1; i >= 0; i--)
      if (d = decorators[i])
        r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
  return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __param = globalThis && globalThis.__param || function(paramIndex, decorator) {
  return function(target, key) {
    decorator(target, key, paramIndex);
  };
};
let InPlaceReplaceController = class InPlaceReplaceController2 {
  constructor(editor, editorWorkerService) {
    this.decorationIds = [];
    this.editor = editor;
    this.editorWorkerService = editorWorkerService;
  }
  static get(editor) {
    return editor.getContribution(InPlaceReplaceController2.ID);
  }
  dispose() {
  }
  run(source, up) {
    if (this.currentRequest) {
      this.currentRequest.cancel();
    }
    const editorSelection = this.editor.getSelection();
    const model = this.editor.getModel();
    if (!model || !editorSelection) {
      return void 0;
    }
    let selection = editorSelection;
    if (selection.startLineNumber !== selection.endLineNumber) {
      return void 0;
    }
    const state = new EditorState(
      this.editor,
      1 | 4
      /* Position */
    );
    const modelURI = model.uri;
    if (!this.editorWorkerService.canNavigateValueSet(modelURI)) {
      return Promise.resolve(void 0);
    }
    this.currentRequest = createCancelablePromise((token) => this.editorWorkerService.navigateValueSet(modelURI, selection, up));
    return this.currentRequest.then((result) => {
      if (!result || !result.range || !result.value) {
        return;
      }
      if (!state.validate(this.editor)) {
        return;
      }
      let editRange = Range.lift(result.range);
      let highlightRange = result.range;
      let diff = result.value.length - (selection.endColumn - selection.startColumn);
      highlightRange = {
        startLineNumber: highlightRange.startLineNumber,
        startColumn: highlightRange.startColumn,
        endLineNumber: highlightRange.endLineNumber,
        endColumn: highlightRange.startColumn + result.value.length
      };
      if (diff > 1) {
        selection = new Selection(selection.startLineNumber, selection.startColumn, selection.endLineNumber, selection.endColumn + diff - 1);
      }
      const command = new InPlaceReplaceCommand(editRange, selection, result.value);
      this.editor.pushUndoStop();
      this.editor.executeCommand(source, command);
      this.editor.pushUndoStop();
      this.decorationIds = this.editor.deltaDecorations(this.decorationIds, [{
        range: highlightRange,
        options: InPlaceReplaceController2.DECORATION
      }]);
      if (this.decorationRemover) {
        this.decorationRemover.cancel();
      }
      this.decorationRemover = timeout(350);
      this.decorationRemover.then(() => this.decorationIds = this.editor.deltaDecorations(this.decorationIds, [])).catch(onUnexpectedError);
    }).catch(onUnexpectedError);
  }
};
InPlaceReplaceController.ID = "editor.contrib.inPlaceReplaceController";
InPlaceReplaceController.DECORATION = ModelDecorationOptions.register({
  description: "in-place-replace",
  className: "valueSetReplacement"
});
InPlaceReplaceController = __decorate([
  __param(1, IEditorWorkerService)
], InPlaceReplaceController);
class InPlaceReplaceUp extends EditorAction {
  constructor() {
    super({
      id: "editor.action.inPlaceReplace.up",
      label: localize("InPlaceReplaceAction.previous.label", "Replace with Previous Value"),
      alias: "Replace with Previous Value",
      precondition: EditorContextKeys.writable,
      kbOpts: {
        kbExpr: EditorContextKeys.editorTextFocus,
        primary: 2048 | 1024 | 82,
        weight: 100
        /* EditorContrib */
      }
    });
  }
  run(accessor, editor) {
    const controller = InPlaceReplaceController.get(editor);
    if (!controller) {
      return Promise.resolve(void 0);
    }
    return controller.run(this.id, true);
  }
}
class InPlaceReplaceDown extends EditorAction {
  constructor() {
    super({
      id: "editor.action.inPlaceReplace.down",
      label: localize("InPlaceReplaceAction.next.label", "Replace with Next Value"),
      alias: "Replace with Next Value",
      precondition: EditorContextKeys.writable,
      kbOpts: {
        kbExpr: EditorContextKeys.editorTextFocus,
        primary: 2048 | 1024 | 84,
        weight: 100
        /* EditorContrib */
      }
    });
  }
  run(accessor, editor) {
    const controller = InPlaceReplaceController.get(editor);
    if (!controller) {
      return Promise.resolve(void 0);
    }
    return controller.run(this.id, false);
  }
}
registerEditorContribution(InPlaceReplaceController.ID, InPlaceReplaceController);
registerEditorAction(InPlaceReplaceUp);
registerEditorAction(InPlaceReplaceDown);
registerThemingParticipant((theme, collector) => {
  const border = theme.getColor(editorBracketMatchBorder);
  if (border) {
    collector.addRule(`.monaco-editor.vs .valueSetReplacement { outline: solid 2px ${border}; }`);
  }
});
