"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const async = require("../../../base/common/async.js");
const cancellation = require("../../../base/common/cancellation.js");
const lifecycle = require("../../../base/common/lifecycle.js");
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.TriggerAction = void 0;
(function(TriggerAction) {
  TriggerAction[TriggerAction["NO_ACTION"] = 0] = "NO_ACTION";
  TriggerAction[TriggerAction["CLOSE_PICKER"] = 1] = "CLOSE_PICKER";
  TriggerAction[TriggerAction["REFRESH_PICKER"] = 2] = "REFRESH_PICKER";
  TriggerAction[TriggerAction["REMOVE_ITEM"] = 3] = "REMOVE_ITEM";
})(exports.TriggerAction || (exports.TriggerAction = {}));
function isPicksWithActive(obj) {
  const candidate = obj;
  return Array.isArray(candidate.items);
}
function isFastAndSlowPicks(obj) {
  const candidate = obj;
  return !!candidate.picks && candidate.additionalPicks instanceof Promise;
}
class PickerQuickAccessProvider extends lifecycle.Disposable {
  constructor(prefix, options) {
    super();
    this.prefix = prefix;
    this.options = options;
  }
  provide(picker, token) {
    var _a;
    const disposables = new lifecycle.DisposableStore();
    picker.canAcceptInBackground = !!((_a = this.options) === null || _a === void 0 ? void 0 : _a.canAcceptInBackground);
    picker.matchOnLabel = picker.matchOnDescription = picker.matchOnDetail = picker.sortByLabel = false;
    let picksCts = void 0;
    const picksDisposable = disposables.add(new lifecycle.MutableDisposable());
    const updatePickerItems = () => __awaiter(this, void 0, void 0, function* () {
      const picksDisposables = picksDisposable.value = new lifecycle.DisposableStore();
      picksCts === null || picksCts === void 0 ? void 0 : picksCts.dispose(true);
      picker.busy = false;
      picksCts = new cancellation.CancellationTokenSource(token);
      const picksToken = picksCts.token;
      const picksFilter = picker.value.substr(this.prefix.length).trim();
      const providedPicks = this._getPicks(picksFilter, picksDisposables, picksToken);
      const applyPicks = (picks, skipEmpty) => {
        var _a2;
        let items;
        let activeItem = void 0;
        if (isPicksWithActive(picks)) {
          items = picks.items;
          activeItem = picks.active;
        } else {
          items = picks;
        }
        if (items.length === 0) {
          if (skipEmpty) {
            return false;
          }
          if (picksFilter.length > 0 && ((_a2 = this.options) === null || _a2 === void 0 ? void 0 : _a2.noResultsPick)) {
            items = [this.options.noResultsPick];
          }
        }
        picker.items = items;
        if (activeItem) {
          picker.activeItems = [activeItem];
        }
        return true;
      };
      if (providedPicks === null)
        ;
      else if (isFastAndSlowPicks(providedPicks)) {
        let fastPicksApplied = false;
        let slowPicksApplied = false;
        yield Promise.all([
          // Fast Picks: to reduce amount of flicker, we race against
          // the slow picks over 500ms and then set the fast picks.
          // If the slow picks are faster, we reduce the flicker by
          // only setting the items once.
          (() => __awaiter(this, void 0, void 0, function* () {
            yield async.timeout(PickerQuickAccessProvider.FAST_PICKS_RACE_DELAY);
            if (picksToken.isCancellationRequested) {
              return;
            }
            if (!slowPicksApplied) {
              fastPicksApplied = applyPicks(
                providedPicks.picks,
                true
                /* skip over empty to reduce flicker */
              );
            }
          }))(),
          // Slow Picks: we await the slow picks and then set them at
          // once together with the fast picks, but only if we actually
          // have additional results.
          (() => __awaiter(this, void 0, void 0, function* () {
            picker.busy = true;
            try {
              const awaitedAdditionalPicks = yield providedPicks.additionalPicks;
              if (picksToken.isCancellationRequested) {
                return;
              }
              let picks;
              let activePick = void 0;
              if (isPicksWithActive(providedPicks.picks)) {
                picks = providedPicks.picks.items;
                activePick = providedPicks.picks.active;
              } else {
                picks = providedPicks.picks;
              }
              let additionalPicks;
              let additionalActivePick = void 0;
              if (isPicksWithActive(awaitedAdditionalPicks)) {
                additionalPicks = awaitedAdditionalPicks.items;
                additionalActivePick = awaitedAdditionalPicks.active;
              } else {
                additionalPicks = awaitedAdditionalPicks;
              }
              if (additionalPicks.length > 0 || !fastPicksApplied) {
                let fallbackActivePick = void 0;
                if (!activePick && !additionalActivePick) {
                  const fallbackActivePickCandidate = picker.activeItems[0];
                  if (fallbackActivePickCandidate && picks.indexOf(fallbackActivePickCandidate) !== -1) {
                    fallbackActivePick = fallbackActivePickCandidate;
                  }
                }
                applyPicks({
                  items: [...picks, ...additionalPicks],
                  active: activePick || additionalActivePick || fallbackActivePick
                });
              }
            } finally {
              if (!picksToken.isCancellationRequested) {
                picker.busy = false;
              }
              slowPicksApplied = true;
            }
          }))()
        ]);
      } else if (!(providedPicks instanceof Promise)) {
        applyPicks(providedPicks);
      } else {
        picker.busy = true;
        try {
          const awaitedPicks = yield providedPicks;
          if (picksToken.isCancellationRequested) {
            return;
          }
          applyPicks(awaitedPicks);
        } finally {
          if (!picksToken.isCancellationRequested) {
            picker.busy = false;
          }
        }
      }
    });
    disposables.add(picker.onDidChangeValue(() => updatePickerItems()));
    updatePickerItems();
    disposables.add(picker.onDidAccept((event) => {
      const [item] = picker.selectedItems;
      if (typeof (item === null || item === void 0 ? void 0 : item.accept) === "function") {
        if (!event.inBackground) {
          picker.hide();
        }
        item.accept(picker.keyMods, event);
      }
    }));
    disposables.add(picker.onDidTriggerItemButton(({ button, item }) => __awaiter(this, void 0, void 0, function* () {
      var _b, _c;
      if (typeof item.trigger === "function") {
        const buttonIndex = (_c = (_b = item.buttons) === null || _b === void 0 ? void 0 : _b.indexOf(button)) !== null && _c !== void 0 ? _c : -1;
        if (buttonIndex >= 0) {
          const result = item.trigger(buttonIndex, picker.keyMods);
          const action = typeof result === "number" ? result : yield result;
          if (token.isCancellationRequested) {
            return;
          }
          switch (action) {
            case exports.TriggerAction.NO_ACTION:
              break;
            case exports.TriggerAction.CLOSE_PICKER:
              picker.hide();
              break;
            case exports.TriggerAction.REFRESH_PICKER:
              updatePickerItems();
              break;
            case exports.TriggerAction.REMOVE_ITEM: {
              const index = picker.items.indexOf(item);
              if (index !== -1) {
                const items = picker.items.slice();
                const removed = items.splice(index, 1);
                const activeItems = picker.activeItems.filter((activeItem) => activeItem !== removed[0]);
                const keepScrollPositionBefore = picker.keepScrollPosition;
                picker.keepScrollPosition = true;
                picker.items = items;
                if (activeItems) {
                  picker.activeItems = activeItems;
                }
                picker.keepScrollPosition = keepScrollPositionBefore;
              }
              break;
            }
          }
        }
      }
    })));
    return disposables;
  }
}
PickerQuickAccessProvider.FAST_PICKS_RACE_DELAY = 200;
exports.PickerQuickAccessProvider = PickerQuickAccessProvider;
