import { getDomNodePagePosition } from "../../../../base/browser/dom.mjs";
import { Separator, Action } from "../../../../base/common/actions.mjs";
import { canceled } from "../../../../base/common/errors.mjs";
import { Lazy } from "../../../../base/common/lazy.mjs";
import { Disposable, MutableDisposable } from "../../../../base/common/lifecycle.mjs";
import { Position } from "../../../common/core/position.mjs";
import { ILanguageFeaturesService } from "../../../common/services/languageFeatures.mjs";
import { CodeActionItem, refactorCommandId, codeActionCommandId, sourceActionCommandId, organizeImportsCommandId, fixAllCommandId } from "./codeAction.mjs";
import { CodeActionKind, CodeActionCommandArgs } from "./types.mjs";
import { IContextMenuService } from "../../../../platform/contextview/browser/contextView.mjs";
import { IKeybindingService } from "../../../../platform/keybinding/common/keybinding.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());
  });
};
class CodeActionAction extends Action {
  constructor(action, callback) {
    super(action.command ? action.command.id : action.title, stripNewlines(action.title), void 0, !action.disabled, callback);
    this.action = action;
  }
}
function stripNewlines(str) {
  return str.replace(/\r\n|\r|\n/g, " ");
}
let CodeActionMenu = class CodeActionMenu2 extends Disposable {
  constructor(_editor, _delegate, _contextMenuService, keybindingService, _languageFeaturesService) {
    super();
    this._editor = _editor;
    this._delegate = _delegate;
    this._contextMenuService = _contextMenuService;
    this._languageFeaturesService = _languageFeaturesService;
    this._visible = false;
    this._showingActions = this._register(new MutableDisposable());
    this._keybindingResolver = new CodeActionKeybindingResolver({
      getKeybindings: () => keybindingService.getKeybindings()
    });
  }
  get isVisible() {
    return this._visible;
  }
  show(trigger, codeActions, at, options) {
    return __awaiter(this, void 0, void 0, function* () {
      const actionsToShow = options.includeDisabledActions ? codeActions.allActions : codeActions.validActions;
      if (!actionsToShow.length) {
        this._visible = false;
        return;
      }
      if (!this._editor.getDomNode()) {
        this._visible = false;
        throw canceled();
      }
      this._visible = true;
      this._showingActions.value = codeActions;
      const menuActions = this.getMenuActions(trigger, actionsToShow, codeActions.documentation);
      const anchor = Position.isIPosition(at) ? this._toCoords(at) : at || { x: 0, y: 0 };
      const resolver = this._keybindingResolver.getResolver();
      const useShadowDOM = this._editor.getOption(
        115
        /* useShadowDOM */
      );
      this._contextMenuService.showContextMenu({
        domForShadowRoot: useShadowDOM ? this._editor.getDomNode() : void 0,
        getAnchor: () => anchor,
        getActions: () => menuActions,
        onHide: () => {
          this._visible = false;
          this._editor.focus();
        },
        autoSelectFirstItem: true,
        getKeyBinding: (action) => action instanceof CodeActionAction ? resolver(action.action) : void 0
      });
    });
  }
  getMenuActions(trigger, actionsToShow, documentation) {
    var _a, _b;
    const toCodeActionAction = (item) => new CodeActionAction(item.action, () => this._delegate.onSelectCodeAction(item));
    const result = actionsToShow.map(toCodeActionAction);
    const allDocumentation = [...documentation];
    const model = this._editor.getModel();
    if (model && result.length) {
      for (const provider of this._languageFeaturesService.codeActionProvider.all(model)) {
        if (provider._getAdditionalMenuItems) {
          allDocumentation.push(...provider._getAdditionalMenuItems({ trigger: trigger.type, only: (_b = (_a = trigger.filter) === null || _a === void 0 ? void 0 : _a.include) === null || _b === void 0 ? void 0 : _b.value }, actionsToShow.map((item) => item.action)));
        }
      }
    }
    if (allDocumentation.length) {
      result.push(new Separator(), ...allDocumentation.map((command) => toCodeActionAction(new CodeActionItem({
        title: command.title,
        command
      }, void 0))));
    }
    return result;
  }
  _toCoords(position) {
    if (!this._editor.hasModel()) {
      return { x: 0, y: 0 };
    }
    this._editor.revealPosition(
      position,
      1
      /* Immediate */
    );
    this._editor.render();
    const cursorCoords = this._editor.getScrolledVisiblePosition(position);
    const editorCoords = getDomNodePagePosition(this._editor.getDomNode());
    const x = editorCoords.left + cursorCoords.left;
    const y = editorCoords.top + cursorCoords.top + cursorCoords.height;
    return { x, y };
  }
};
CodeActionMenu = __decorate([
  __param(2, IContextMenuService),
  __param(3, IKeybindingService),
  __param(4, ILanguageFeaturesService)
], CodeActionMenu);
class CodeActionKeybindingResolver {
  constructor(_keybindingProvider) {
    this._keybindingProvider = _keybindingProvider;
  }
  getResolver() {
    const allCodeActionBindings = new Lazy(() => this._keybindingProvider.getKeybindings().filter((item) => CodeActionKeybindingResolver.codeActionCommands.indexOf(item.command) >= 0).filter((item) => item.resolvedKeybinding).map((item) => {
      let commandArgs = item.commandArgs;
      if (item.command === organizeImportsCommandId) {
        commandArgs = { kind: CodeActionKind.SourceOrganizeImports.value };
      } else if (item.command === fixAllCommandId) {
        commandArgs = { kind: CodeActionKind.SourceFixAll.value };
      }
      return Object.assign({ resolvedKeybinding: item.resolvedKeybinding }, CodeActionCommandArgs.fromUser(commandArgs, {
        kind: CodeActionKind.None,
        apply: "never"
        /* Never */
      }));
    }));
    return (action) => {
      if (action.kind) {
        const binding = this.bestKeybindingForCodeAction(action, allCodeActionBindings.getValue());
        return binding === null || binding === void 0 ? void 0 : binding.resolvedKeybinding;
      }
      return void 0;
    };
  }
  bestKeybindingForCodeAction(action, candidates) {
    if (!action.kind) {
      return void 0;
    }
    const kind = new CodeActionKind(action.kind);
    return candidates.filter((candidate) => candidate.kind.contains(kind)).filter((candidate) => {
      if (candidate.preferred) {
        return action.isPreferred;
      }
      return true;
    }).reduceRight((currentBest, candidate) => {
      if (!currentBest) {
        return candidate;
      }
      return currentBest.kind.contains(candidate.kind) ? candidate : currentBest;
    }, void 0);
  }
}
CodeActionKeybindingResolver.codeActionCommands = [
  refactorCommandId,
  codeActionCommandId,
  sourceActionCommandId,
  organizeImportsCommandId,
  fixAllCommandId
];
export {
  CodeActionKeybindingResolver,
  CodeActionMenu
};
