"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const async = require("../../../../base/common/async.js");
const errors = require("../../../../base/common/errors.js");
const lifecycle = require("../../../../base/common/lifecycle.js");
const languages = require("../../../common/languages.js");
const languageFeatures = require("../../../common/services/languageFeatures.js");
const ghostText = require("./ghostText.js");
const inlineCompletionsModel = require("./inlineCompletionsModel.js");
const inlineCompletionToGhostText = require("./inlineCompletionToGhostText.js");
const suggestWidgetInlineCompletionProvider = require("./suggestWidgetInlineCompletionProvider.js");
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);
  };
};
var __awaiter = globalThis && globalThis.__awaiter || function(thisArg, _arguments, P, generator) {
  function adopt(value) {
    return value instanceof P ? value : new P(function(resolve) {
      resolve(value);
    });
  }
  return new (P || (P = Promise))(function(resolve, reject) {
    function fulfilled(value) {
      try {
        step(generator.next(value));
      } catch (e) {
        reject(e);
      }
    }
    function rejected(value) {
      try {
        step(generator["throw"](value));
      } catch (e) {
        reject(e);
      }
    }
    function step(result) {
      result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
    }
    step((generator = generator.apply(thisArg, _arguments || [])).next());
  });
};
exports.SuggestWidgetPreviewModel = class SuggestWidgetPreviewModel extends ghostText.BaseGhostTextWidgetModel {
  constructor(editor, cache, languageFeaturesService) {
    super(editor);
    this.cache = cache;
    this.languageFeaturesService = languageFeaturesService;
    this.suggestionInlineCompletionSource = this._register(new suggestWidgetInlineCompletionProvider.SuggestWidgetInlineCompletionProvider(
      this.editor,
      // Use the first cache item (if any) as preselection.
      () => {
        var _a, _b;
        return (_b = (_a = this.cache.value) === null || _a === void 0 ? void 0 : _a.completions[0]) === null || _b === void 0 ? void 0 : _b.toLiveInlineCompletion();
      }
    ));
    this.updateOperation = this._register(new lifecycle.MutableDisposable());
    this.updateCacheSoon = this._register(new async.RunOnceScheduler(() => this.updateCache(), 50));
    this.minReservedLineCount = 0;
    this._register(this.suggestionInlineCompletionSource.onDidChange(() => {
      this.updateCacheSoon.schedule();
      const suggestWidgetState = this.suggestionInlineCompletionSource.state;
      if (!suggestWidgetState) {
        this.minReservedLineCount = 0;
      }
      const newGhostText = this.ghostText;
      if (newGhostText) {
        this.minReservedLineCount = Math.max(this.minReservedLineCount, sum(newGhostText.parts.map((p) => p.lines.length - 1)));
      }
      if (this.minReservedLineCount >= 1) {
        this.suggestionInlineCompletionSource.forceRenderingAbove();
      } else {
        this.suggestionInlineCompletionSource.stopForceRenderingAbove();
      }
      this.onDidChangeEmitter.fire();
    }));
    this._register(this.cache.onDidChange(() => {
      this.onDidChangeEmitter.fire();
    }));
    this._register(this.editor.onDidChangeCursorPosition((e) => {
      this.minReservedLineCount = 0;
      this.updateCacheSoon.schedule();
      this.onDidChangeEmitter.fire();
    }));
    this._register(lifecycle.toDisposable(() => this.suggestionInlineCompletionSource.stopForceRenderingAbove()));
  }
  get isActive() {
    return this.suggestionInlineCompletionSource.state !== void 0;
  }
  isSuggestionPreviewEnabled() {
    const suggestOptions = this.editor.getOption(
      106
      /* suggest */
    );
    return suggestOptions.preview;
  }
  updateCache() {
    return __awaiter(this, void 0, void 0, function* () {
      const state = this.suggestionInlineCompletionSource.state;
      if (!state || !state.selectedItem) {
        return;
      }
      const info = {
        text: state.selectedItem.normalizedInlineCompletion.text,
        range: state.selectedItem.normalizedInlineCompletion.range,
        isSnippetText: state.selectedItem.isSnippetText,
        completionKind: state.selectedItem.completionItemKind
      };
      const position = this.editor.getPosition();
      const promise = async.createCancelablePromise((token) => __awaiter(this, void 0, void 0, function* () {
        let result;
        try {
          result = yield inlineCompletionsModel.provideInlineCompletions(this.languageFeaturesService.inlineCompletionsProvider, position, this.editor.getModel(), { triggerKind: languages.InlineCompletionTriggerKind.Automatic, selectedSuggestionInfo: info }, token);
        } catch (e) {
          errors.onUnexpectedError(e);
          return;
        }
        if (token.isCancellationRequested) {
          return;
        }
        this.cache.setValue(this.editor, result, languages.InlineCompletionTriggerKind.Automatic);
        this.onDidChangeEmitter.fire();
      }));
      const operation = new inlineCompletionsModel.UpdateOperation(promise, languages.InlineCompletionTriggerKind.Automatic);
      this.updateOperation.value = operation;
      yield promise;
      if (this.updateOperation.value === operation) {
        this.updateOperation.clear();
      }
    });
  }
  get ghostText() {
    var _a, _b, _c;
    const isSuggestionPreviewEnabled = this.isSuggestionPreviewEnabled();
    const augmentedCompletion = inlineCompletionsModel.minimizeInlineCompletion(this.editor.getModel(), (_b = (_a = this.cache.value) === null || _a === void 0 ? void 0 : _a.completions[0]) === null || _b === void 0 ? void 0 : _b.toLiveInlineCompletion());
    const suggestWidgetState = this.suggestionInlineCompletionSource.state;
    const suggestInlineCompletion = inlineCompletionsModel.minimizeInlineCompletion(this.editor.getModel(), (_c = suggestWidgetState === null || suggestWidgetState === void 0 ? void 0 : suggestWidgetState.selectedItem) === null || _c === void 0 ? void 0 : _c.normalizedInlineCompletion);
    const isAugmentedCompletionValid = augmentedCompletion && suggestInlineCompletion && augmentedCompletion.text.startsWith(suggestInlineCompletion.text) && augmentedCompletion.range.equalsRange(suggestInlineCompletion.range);
    if (!isSuggestionPreviewEnabled && !isAugmentedCompletionValid) {
      return void 0;
    }
    const finalCompletion = isAugmentedCompletionValid ? augmentedCompletion : suggestInlineCompletion || augmentedCompletion;
    const inlineCompletionPreviewLength = isAugmentedCompletionValid ? finalCompletion.text.length - suggestInlineCompletion.text.length : 0;
    const newGhostText = this.toGhostText(finalCompletion, inlineCompletionPreviewLength);
    return newGhostText;
  }
  toGhostText(completion, inlineCompletionPreviewLength) {
    const mode = this.editor.getOptions().get(
      106
      /* suggest */
    ).previewMode;
    return completion ? inlineCompletionToGhostText.inlineCompletionToGhostText(completion, this.editor.getModel(), mode, this.editor.getPosition(), inlineCompletionPreviewLength) || // Show an invisible ghost text to reserve space
    new ghostText.GhostText(completion.range.endLineNumber, [], this.minReservedLineCount) : void 0;
  }
};
exports.SuggestWidgetPreviewModel = __decorate([
  __param(2, languageFeatures.ILanguageFeaturesService)
], exports.SuggestWidgetPreviewModel);
function sum(arr) {
  return arr.reduce((a, b) => a + b, 0);
}
