import { toErrorMessage } from "../../../base/common/errorMessage.mjs";
import { isCancellationError } from "../../../base/common/errors.mjs";
import { or, matchesContiguousSubString, matchesWords, matchesPrefix } from "../../../base/common/filters.mjs";
import { Disposable } from "../../../base/common/lifecycle.mjs";
import { LRUCache } from "../../../base/common/map.mjs";
import Severity from "../../../base/common/severity.mjs";
import { withNullAsUndefined } from "../../../base/common/types.mjs";
import { localize } from "../../../nls.mjs";
import { ICommandService } from "../../commands/common/commands.mjs";
import { IConfigurationService } from "../../configuration/common/configuration.mjs";
import { IDialogService } from "../../dialogs/common/dialogs.mjs";
import { IInstantiationService } from "../../instantiation/common/instantiation.mjs";
import { IKeybindingService } from "../../keybinding/common/keybinding.mjs";
import { PickerQuickAccessProvider } from "./pickerQuickAccess.mjs";
import { IStorageService } from "../../storage/common/storage.mjs";
import { ITelemetryService } from "../../telemetry/common/telemetry.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);
  };
};
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());
  });
};
let AbstractCommandsQuickAccessProvider = class AbstractCommandsQuickAccessProvider2 extends PickerQuickAccessProvider {
  constructor(options, instantiationService, keybindingService, commandService, telemetryService, dialogService) {
    super(AbstractCommandsQuickAccessProvider2.PREFIX, options);
    this.instantiationService = instantiationService;
    this.keybindingService = keybindingService;
    this.commandService = commandService;
    this.telemetryService = telemetryService;
    this.dialogService = dialogService;
    this.commandsHistory = this._register(this.instantiationService.createInstance(CommandsHistory));
    this.options = options;
  }
  _getPicks(filter, disposables, token) {
    return __awaiter(this, void 0, void 0, function* () {
      const allCommandPicks = yield this.getCommandPicks(disposables, token);
      if (token.isCancellationRequested) {
        return [];
      }
      const filteredCommandPicks = [];
      for (const commandPick of allCommandPicks) {
        const labelHighlights = withNullAsUndefined(AbstractCommandsQuickAccessProvider2.WORD_FILTER(filter, commandPick.label));
        const aliasHighlights = commandPick.commandAlias ? withNullAsUndefined(AbstractCommandsQuickAccessProvider2.WORD_FILTER(filter, commandPick.commandAlias)) : void 0;
        if (labelHighlights || aliasHighlights) {
          commandPick.highlights = {
            label: labelHighlights,
            detail: this.options.showAlias ? aliasHighlights : void 0
          };
          filteredCommandPicks.push(commandPick);
        } else if (filter === commandPick.commandId) {
          filteredCommandPicks.push(commandPick);
        }
      }
      const mapLabelToCommand = /* @__PURE__ */ new Map();
      for (const commandPick of filteredCommandPicks) {
        const existingCommandForLabel = mapLabelToCommand.get(commandPick.label);
        if (existingCommandForLabel) {
          commandPick.description = commandPick.commandId;
          existingCommandForLabel.description = existingCommandForLabel.commandId;
        } else {
          mapLabelToCommand.set(commandPick.label, commandPick);
        }
      }
      filteredCommandPicks.sort((commandPickA, commandPickB) => {
        const commandACounter = this.commandsHistory.peek(commandPickA.commandId);
        const commandBCounter = this.commandsHistory.peek(commandPickB.commandId);
        if (commandACounter && commandBCounter) {
          return commandACounter > commandBCounter ? -1 : 1;
        }
        if (commandACounter) {
          return -1;
        }
        if (commandBCounter) {
          return 1;
        }
        return commandPickA.label.localeCompare(commandPickB.label);
      });
      const commandPicks = [];
      let addSeparator = false;
      for (let i = 0; i < filteredCommandPicks.length; i++) {
        const commandPick = filteredCommandPicks[i];
        const keybinding = this.keybindingService.lookupKeybinding(commandPick.commandId);
        const ariaLabel = keybinding ? localize("commandPickAriaLabelWithKeybinding", "{0}, {1}", commandPick.label, keybinding.getAriaLabel()) : commandPick.label;
        if (i === 0 && this.commandsHistory.peek(commandPick.commandId)) {
          commandPicks.push({ type: "separator", label: localize("recentlyUsed", "recently used") });
          addSeparator = true;
        }
        if (i !== 0 && addSeparator && !this.commandsHistory.peek(commandPick.commandId)) {
          commandPicks.push({ type: "separator", label: localize("morecCommands", "other commands") });
          addSeparator = false;
        }
        commandPicks.push(Object.assign(Object.assign({}, commandPick), { ariaLabel, detail: this.options.showAlias && commandPick.commandAlias !== commandPick.label ? commandPick.commandAlias : void 0, keybinding, accept: () => __awaiter(this, void 0, void 0, function* () {
          this.commandsHistory.push(commandPick.commandId);
          this.telemetryService.publicLog2("workbenchActionExecuted", {
            id: commandPick.commandId,
            from: "quick open"
          });
          try {
            yield this.commandService.executeCommand(commandPick.commandId);
          } catch (error) {
            if (!isCancellationError(error)) {
              this.dialogService.show(Severity.Error, localize("canNotRun", "Command '{0}' resulted in an error ({1})", commandPick.label, toErrorMessage(error)));
            }
          }
        }) }));
      }
      return commandPicks;
    });
  }
};
AbstractCommandsQuickAccessProvider.PREFIX = ">";
AbstractCommandsQuickAccessProvider.WORD_FILTER = or(matchesPrefix, matchesWords, matchesContiguousSubString);
AbstractCommandsQuickAccessProvider = __decorate([
  __param(1, IInstantiationService),
  __param(2, IKeybindingService),
  __param(3, ICommandService),
  __param(4, ITelemetryService),
  __param(5, IDialogService)
], AbstractCommandsQuickAccessProvider);
let CommandsHistory = class CommandsHistory2 extends Disposable {
  constructor(storageService, configurationService) {
    super();
    this.storageService = storageService;
    this.configurationService = configurationService;
    this.configuredCommandsHistoryLength = 0;
    this.updateConfiguration();
    this.load();
    this.registerListeners();
  }
  registerListeners() {
    this._register(this.configurationService.onDidChangeConfiguration(() => this.updateConfiguration()));
  }
  updateConfiguration() {
    this.configuredCommandsHistoryLength = CommandsHistory2.getConfiguredCommandHistoryLength(this.configurationService);
    if (CommandsHistory2.cache && CommandsHistory2.cache.limit !== this.configuredCommandsHistoryLength) {
      CommandsHistory2.cache.limit = this.configuredCommandsHistoryLength;
      CommandsHistory2.saveState(this.storageService);
    }
  }
  load() {
    const raw = this.storageService.get(
      CommandsHistory2.PREF_KEY_CACHE,
      0
      /* GLOBAL */
    );
    let serializedCache;
    if (raw) {
      try {
        serializedCache = JSON.parse(raw);
      } catch (error) {
      }
    }
    const cache = CommandsHistory2.cache = new LRUCache(this.configuredCommandsHistoryLength, 1);
    if (serializedCache) {
      let entries;
      if (serializedCache.usesLRU) {
        entries = serializedCache.entries;
      } else {
        entries = serializedCache.entries.sort((a, b) => a.value - b.value);
      }
      entries.forEach((entry) => cache.set(entry.key, entry.value));
    }
    CommandsHistory2.counter = this.storageService.getNumber(CommandsHistory2.PREF_KEY_COUNTER, 0, CommandsHistory2.counter);
  }
  push(commandId) {
    if (!CommandsHistory2.cache) {
      return;
    }
    CommandsHistory2.cache.set(commandId, CommandsHistory2.counter++);
    CommandsHistory2.saveState(this.storageService);
  }
  peek(commandId) {
    var _a;
    return (_a = CommandsHistory2.cache) === null || _a === void 0 ? void 0 : _a.peek(commandId);
  }
  static saveState(storageService) {
    if (!CommandsHistory2.cache) {
      return;
    }
    const serializedCache = { usesLRU: true, entries: [] };
    CommandsHistory2.cache.forEach((value, key) => serializedCache.entries.push({ key, value }));
    storageService.store(
      CommandsHistory2.PREF_KEY_CACHE,
      JSON.stringify(serializedCache),
      0,
      0
      /* USER */
    );
    storageService.store(
      CommandsHistory2.PREF_KEY_COUNTER,
      CommandsHistory2.counter,
      0,
      0
      /* USER */
    );
  }
  static getConfiguredCommandHistoryLength(configurationService) {
    var _a, _b;
    const config = configurationService.getValue();
    const configuredCommandHistoryLength = (_b = (_a = config.workbench) === null || _a === void 0 ? void 0 : _a.commandPalette) === null || _b === void 0 ? void 0 : _b.history;
    if (typeof configuredCommandHistoryLength === "number") {
      return configuredCommandHistoryLength;
    }
    return CommandsHistory2.DEFAULT_COMMANDS_HISTORY_LENGTH;
  }
};
CommandsHistory.DEFAULT_COMMANDS_HISTORY_LENGTH = 50;
CommandsHistory.PREF_KEY_CACHE = "commandPalette.mru.cache";
CommandsHistory.PREF_KEY_COUNTER = "commandPalette.mru.counter";
CommandsHistory.counter = 1;
CommandsHistory = __decorate([
  __param(0, IStorageService),
  __param(1, IConfigurationService)
], CommandsHistory);
export {
  AbstractCommandsQuickAccessProvider,
  CommandsHistory
};
