"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const async = require("../../../../base/common/async.js");
const errors = require("../../../../base/common/errors.js");
const event = require("../../../../base/common/event.js");
const lifecycle = require("../../../../base/common/lifecycle.js");
const resources = require("../../../../base/common/resources.js");
const range = require("../../../common/core/range.js");
const contextkey = require("../../../../platform/contextkey/common/contextkey.js");
const progress = require("../../../../platform/progress/common/progress.js");
const codeAction = require("./codeAction.js");
var __classPrivateFieldGet = globalThis && globalThis.__classPrivateFieldGet || function(receiver, state, kind, f) {
  if (kind === "a" && !f)
    throw new TypeError("Private accessor was defined without a getter");
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver))
    throw new TypeError("Cannot read private member from an object whose class did not declare it");
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var __classPrivateFieldSet = globalThis && globalThis.__classPrivateFieldSet || function(receiver, state, value, kind, f) {
  if (kind === "m")
    throw new TypeError("Private method is not writable");
  if (kind === "a" && !f)
    throw new TypeError("Private accessor was defined without a setter");
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver))
    throw new TypeError("Cannot write private member to an object whose class did not declare it");
  return kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;
};
var _CodeActionModel_isDisposed;
const SUPPORTED_CODE_ACTIONS = new contextkey.RawContextKey("supportedCodeAction", "");
class CodeActionOracle extends lifecycle.Disposable {
  constructor(_editor, _markerService, _signalChange, _delay = 250) {
    super();
    this._editor = _editor;
    this._markerService = _markerService;
    this._signalChange = _signalChange;
    this._delay = _delay;
    this._autoTriggerTimer = this._register(new async.TimeoutTimer());
    this._register(this._markerService.onMarkerChanged((e) => this._onMarkerChanges(e)));
    this._register(this._editor.onDidChangeCursorPosition(() => this._onCursorChange()));
  }
  trigger(trigger) {
    const selection = this._getRangeOfSelectionUnlessWhitespaceEnclosed(trigger);
    return this._createEventAndSignalChange(trigger, selection);
  }
  _onMarkerChanges(resources$1) {
    const model = this._editor.getModel();
    if (!model) {
      return;
    }
    if (resources$1.some((resource) => resources.isEqual(resource, model.uri))) {
      this._autoTriggerTimer.cancelAndSet(() => {
        this.trigger({
          type: 2
          /* Auto */
        });
      }, this._delay);
    }
  }
  _onCursorChange() {
    this._autoTriggerTimer.cancelAndSet(() => {
      this.trigger({
        type: 2
        /* Auto */
      });
    }, this._delay);
  }
  _getRangeOfMarker(selection) {
    const model = this._editor.getModel();
    if (!model) {
      return void 0;
    }
    for (const marker of this._markerService.read({ resource: model.uri })) {
      const markerRange = model.validateRange(marker);
      if (range.Range.intersectRanges(markerRange, selection)) {
        return range.Range.lift(markerRange);
      }
    }
    return void 0;
  }
  _getRangeOfSelectionUnlessWhitespaceEnclosed(trigger) {
    if (!this._editor.hasModel()) {
      return void 0;
    }
    const model = this._editor.getModel();
    const selection = this._editor.getSelection();
    if (selection.isEmpty() && trigger.type === 2) {
      const { lineNumber, column } = selection.getPosition();
      const line = model.getLineContent(lineNumber);
      if (line.length === 0) {
        return void 0;
      } else if (column === 1) {
        if (/\s/.test(line[0])) {
          return void 0;
        }
      } else if (column === model.getLineMaxColumn(lineNumber)) {
        if (/\s/.test(line[line.length - 1])) {
          return void 0;
        }
      } else {
        if (/\s/.test(line[column - 2]) && /\s/.test(line[column - 1])) {
          return void 0;
        }
      }
    }
    return selection;
  }
  _createEventAndSignalChange(trigger, selection) {
    const model = this._editor.getModel();
    if (!selection || !model) {
      this._signalChange(void 0);
      return void 0;
    }
    const markerRange = this._getRangeOfMarker(selection);
    const position = markerRange ? markerRange.getStartPosition() : selection.getStartPosition();
    const e = {
      trigger,
      selection,
      position
    };
    this._signalChange(e);
    return e;
  }
}
exports.CodeActionsState = void 0;
(function(CodeActionsState) {
  CodeActionsState.Empty = {
    type: 0
    /* Empty */
  };
  class Triggered {
    constructor(trigger, rangeOrSelection, position, _cancellablePromise) {
      this.trigger = trigger;
      this.rangeOrSelection = rangeOrSelection;
      this.position = position;
      this._cancellablePromise = _cancellablePromise;
      this.type = 1;
      this.actions = _cancellablePromise.catch((e) => {
        if (errors.isCancellationError(e)) {
          return emptyCodeActionSet;
        }
        throw e;
      });
    }
    cancel() {
      this._cancellablePromise.cancel();
    }
  }
  CodeActionsState.Triggered = Triggered;
})(exports.CodeActionsState || (exports.CodeActionsState = {}));
const emptyCodeActionSet = {
  allActions: [],
  validActions: [],
  dispose: () => {
  },
  documentation: [],
  hasAutoFix: false
};
class CodeActionModel extends lifecycle.Disposable {
  constructor(_editor, _registry, _markerService, contextKeyService, _progressService) {
    super();
    this._editor = _editor;
    this._registry = _registry;
    this._markerService = _markerService;
    this._progressService = _progressService;
    this._codeActionOracle = this._register(new lifecycle.MutableDisposable());
    this._state = exports.CodeActionsState.Empty;
    this._onDidChangeState = this._register(new event.Emitter());
    this.onDidChangeState = this._onDidChangeState.event;
    _CodeActionModel_isDisposed.set(this, false);
    this._supportedCodeActions = SUPPORTED_CODE_ACTIONS.bindTo(contextKeyService);
    this._register(this._editor.onDidChangeModel(() => this._update()));
    this._register(this._editor.onDidChangeModelLanguage(() => this._update()));
    this._register(this._registry.onDidChange(() => this._update()));
    this._update();
  }
  dispose() {
    if (__classPrivateFieldGet(this, _CodeActionModel_isDisposed, "f")) {
      return;
    }
    __classPrivateFieldSet(this, _CodeActionModel_isDisposed, true, "f");
    super.dispose();
    this.setState(exports.CodeActionsState.Empty, true);
  }
  _update() {
    if (__classPrivateFieldGet(this, _CodeActionModel_isDisposed, "f")) {
      return;
    }
    this._codeActionOracle.value = void 0;
    this.setState(exports.CodeActionsState.Empty);
    const model = this._editor.getModel();
    if (model && this._registry.has(model) && !this._editor.getOption(
      81
      /* readOnly */
    )) {
      const supportedActions = [];
      for (const provider of this._registry.all(model)) {
        if (Array.isArray(provider.providedCodeActionKinds)) {
          supportedActions.push(...provider.providedCodeActionKinds);
        }
      }
      this._supportedCodeActions.set(supportedActions.join(" "));
      this._codeActionOracle.value = new CodeActionOracle(this._editor, this._markerService, (trigger) => {
        var _a;
        if (!trigger) {
          this.setState(exports.CodeActionsState.Empty);
          return;
        }
        const actions = async.createCancelablePromise((token) => codeAction.getCodeActions(this._registry, model, trigger.selection, trigger.trigger, progress.Progress.None, token));
        if (trigger.trigger.type === 1) {
          (_a = this._progressService) === null || _a === void 0 ? void 0 : _a.showWhile(actions, 250);
        }
        this.setState(new exports.CodeActionsState.Triggered(trigger.trigger, trigger.selection, trigger.position, actions));
      }, void 0);
      this._codeActionOracle.value.trigger({
        type: 2
        /* Auto */
      });
    } else {
      this._supportedCodeActions.reset();
    }
  }
  trigger(trigger) {
    if (this._codeActionOracle.value) {
      this._codeActionOracle.value.trigger(trigger);
    }
  }
  setState(newState, skipNotify) {
    if (newState === this._state) {
      return;
    }
    if (this._state.type === 1) {
      this._state.cancel();
    }
    this._state = newState;
    if (!skipNotify && !__classPrivateFieldGet(this, _CodeActionModel_isDisposed, "f")) {
      this._onDidChangeState.fire(newState);
    }
  }
}
_CodeActionModel_isDisposed = /* @__PURE__ */ new WeakMap();
exports.CodeActionModel = CodeActionModel;
exports.SUPPORTED_CODE_ACTIONS = SUPPORTED_CODE_ACTIONS;
