import { CancellationToken } from "../../../../base/common/cancellation.mjs";
import { Lazy } from "../../../../base/common/lazy.mjs";
import { Disposable } from "../../../../base/common/lifecycle.mjs";
import { escapeRegExpCharacters } from "../../../../base/common/strings.mjs";
import { EditorAction, EditorCommand } from "../../../browser/editorExtensions.mjs";
import { IBulkEditService, ResourceEdit } from "../../../browser/services/bulkEditService.mjs";
import { EditorContextKeys } from "../../../common/editorContextKeys.mjs";
import { ILanguageFeaturesService } from "../../../common/services/languageFeatures.mjs";
import { codeActionCommandId, refactorCommandId, sourceActionCommandId, organizeImportsCommandId, fixAllCommandId } from "./codeAction.mjs";
import { CodeActionUi } from "./codeActionUi.mjs";
import { MessageController } from "../../message/browser/messageController.mjs";
import { localize } from "../../../../nls.mjs";
import { ICommandService } from "../../../../platform/commands/common/commands.mjs";
import { IContextKeyService, ContextKeyExpr } from "../../../../platform/contextkey/common/contextkey.mjs";
import { IInstantiationService } from "../../../../platform/instantiation/common/instantiation.mjs";
import { IMarkerService } from "../../../../platform/markers/common/markers.mjs";
import { INotificationService } from "../../../../platform/notification/common/notification.mjs";
import { IEditorProgressService } from "../../../../platform/progress/common/progress.mjs";
import { ITelemetryService } from "../../../../platform/telemetry/common/telemetry.mjs";
import { CodeActionModel, SUPPORTED_CODE_ACTIONS } from "./codeActionModel.mjs";
import { CodeActionCommandArgs, CodeActionKind } from "./types.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());
  });
};
function contextKeyForSupportedActions(kind) {
  return ContextKeyExpr.regex(SUPPORTED_CODE_ACTIONS.keys()[0], new RegExp("(\\s|^)" + escapeRegExpCharacters(kind.value) + "\\b"));
}
const argsSchema = {
  type: "object",
  defaultSnippets: [{ body: { kind: "" } }],
  properties: {
    "kind": {
      type: "string",
      description: localize("args.schema.kind", "Kind of the code action to run.")
    },
    "apply": {
      type: "string",
      description: localize("args.schema.apply", "Controls when the returned actions are applied."),
      default: "ifSingle",
      enum: [
        "first",
        "ifSingle",
        "never"
        /* Never */
      ],
      enumDescriptions: [
        localize("args.schema.apply.first", "Always apply the first returned code action."),
        localize("args.schema.apply.ifSingle", "Apply the first returned code action if it is the only one."),
        localize("args.schema.apply.never", "Do not apply the returned code actions.")
      ]
    },
    "preferred": {
      type: "boolean",
      default: false,
      description: localize("args.schema.preferred", "Controls if only preferred code actions should be returned.")
    }
  }
};
let QuickFixController = class QuickFixController2 extends Disposable {
  constructor(editor, markerService, contextKeyService, progressService, _instantiationService, languageFeaturesService) {
    super();
    this._instantiationService = _instantiationService;
    this._editor = editor;
    this._model = this._register(new CodeActionModel(this._editor, languageFeaturesService.codeActionProvider, markerService, contextKeyService, progressService));
    this._register(this._model.onDidChangeState((newState) => this.update(newState)));
    this._ui = new Lazy(() => this._register(new CodeActionUi(editor, QuickFixAction.Id, AutoFixAction.Id, {
      applyCodeAction: (action, retrigger) => __awaiter(this, void 0, void 0, function* () {
        try {
          yield this._applyCodeAction(action);
        } finally {
          if (retrigger) {
            this._trigger({ type: 2, filter: {} });
          }
        }
      })
    }, this._instantiationService)));
  }
  static get(editor) {
    return editor.getContribution(QuickFixController2.ID);
  }
  update(newState) {
    this._ui.getValue().update(newState);
  }
  showCodeActions(trigger, actions, at) {
    return this._ui.getValue().showCodeActionList(trigger, actions, at, { includeDisabledActions: false });
  }
  manualTriggerAtCurrentPosition(notAvailableMessage, filter, autoApply) {
    var _a;
    if (!this._editor.hasModel()) {
      return;
    }
    (_a = MessageController.get(this._editor)) === null || _a === void 0 ? void 0 : _a.closeMessage();
    const triggerPosition = this._editor.getPosition();
    this._trigger({ type: 1, filter, autoApply, context: { notAvailableMessage, position: triggerPosition } });
  }
  _trigger(trigger) {
    return this._model.trigger(trigger);
  }
  _applyCodeAction(action) {
    return this._instantiationService.invokeFunction(applyCodeAction, action, this._editor);
  }
};
QuickFixController.ID = "editor.contrib.quickFixController";
QuickFixController = __decorate([
  __param(1, IMarkerService),
  __param(2, IContextKeyService),
  __param(3, IEditorProgressService),
  __param(4, IInstantiationService),
  __param(5, ILanguageFeaturesService)
], QuickFixController);
function applyCodeAction(accessor, item, editor) {
  return __awaiter(this, void 0, void 0, function* () {
    const bulkEditService = accessor.get(IBulkEditService);
    const commandService = accessor.get(ICommandService);
    const telemetryService = accessor.get(ITelemetryService);
    const notificationService = accessor.get(INotificationService);
    telemetryService.publicLog2("codeAction.applyCodeAction", {
      codeActionTitle: item.action.title,
      codeActionKind: item.action.kind,
      codeActionIsPreferred: !!item.action.isPreferred
    });
    yield item.resolve(CancellationToken.None);
    if (item.action.edit) {
      yield bulkEditService.apply(ResourceEdit.convert(item.action.edit), { editor, label: item.action.title });
    }
    if (item.action.command) {
      try {
        yield commandService.executeCommand(item.action.command.id, ...item.action.command.arguments || []);
      } catch (err) {
        const message = asMessage(err);
        notificationService.error(typeof message === "string" ? message : localize("applyCodeActionFailed", "An unknown error occurred while applying the code action"));
      }
    }
  });
}
function asMessage(err) {
  if (typeof err === "string") {
    return err;
  } else if (err instanceof Error && typeof err.message === "string") {
    return err.message;
  } else {
    return void 0;
  }
}
function triggerCodeActionsForEditorSelection(editor, notAvailableMessage, filter, autoApply) {
  if (editor.hasModel()) {
    const controller = QuickFixController.get(editor);
    if (controller) {
      controller.manualTriggerAtCurrentPosition(notAvailableMessage, filter, autoApply);
    }
  }
}
class QuickFixAction extends EditorAction {
  constructor() {
    super({
      id: QuickFixAction.Id,
      label: localize("quickfix.trigger.label", "Quick Fix..."),
      alias: "Quick Fix...",
      precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider),
      kbOpts: {
        kbExpr: EditorContextKeys.editorTextFocus,
        primary: 2048 | 84,
        weight: 100
        /* EditorContrib */
      }
    });
  }
  run(_accessor, editor) {
    return triggerCodeActionsForEditorSelection(editor, localize("editor.action.quickFix.noneMessage", "No code actions available"), void 0, void 0);
  }
}
QuickFixAction.Id = "editor.action.quickFix";
class CodeActionCommand extends EditorCommand {
  constructor() {
    super({
      id: codeActionCommandId,
      precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider),
      description: {
        description: "Trigger a code action",
        args: [{ name: "args", schema: argsSchema }]
      }
    });
  }
  runEditorCommand(_accessor, editor, userArgs) {
    const args = CodeActionCommandArgs.fromUser(userArgs, {
      kind: CodeActionKind.Empty,
      apply: "ifSingle"
    });
    return triggerCodeActionsForEditorSelection(editor, typeof (userArgs === null || userArgs === void 0 ? void 0 : userArgs.kind) === "string" ? args.preferred ? localize("editor.action.codeAction.noneMessage.preferred.kind", "No preferred code actions for '{0}' available", userArgs.kind) : localize("editor.action.codeAction.noneMessage.kind", "No code actions for '{0}' available", userArgs.kind) : args.preferred ? localize("editor.action.codeAction.noneMessage.preferred", "No preferred code actions available") : localize("editor.action.codeAction.noneMessage", "No code actions available"), {
      include: args.kind,
      includeSourceActions: true,
      onlyIncludePreferredActions: args.preferred
    }, args.apply);
  }
}
class RefactorAction extends EditorAction {
  constructor() {
    super({
      id: refactorCommandId,
      label: localize("refactor.label", "Refactor..."),
      alias: "Refactor...",
      precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider),
      kbOpts: {
        kbExpr: EditorContextKeys.editorTextFocus,
        primary: 2048 | 1024 | 48,
        mac: {
          primary: 256 | 1024 | 48
          /* KeyR */
        },
        weight: 100
        /* EditorContrib */
      },
      contextMenuOpts: {
        group: "1_modification",
        order: 2,
        when: ContextKeyExpr.and(EditorContextKeys.writable, contextKeyForSupportedActions(CodeActionKind.Refactor))
      },
      description: {
        description: "Refactor...",
        args: [{ name: "args", schema: argsSchema }]
      }
    });
  }
  run(_accessor, editor, userArgs) {
    const args = CodeActionCommandArgs.fromUser(userArgs, {
      kind: CodeActionKind.Refactor,
      apply: "never"
      /* Never */
    });
    return triggerCodeActionsForEditorSelection(editor, typeof (userArgs === null || userArgs === void 0 ? void 0 : userArgs.kind) === "string" ? args.preferred ? localize("editor.action.refactor.noneMessage.preferred.kind", "No preferred refactorings for '{0}' available", userArgs.kind) : localize("editor.action.refactor.noneMessage.kind", "No refactorings for '{0}' available", userArgs.kind) : args.preferred ? localize("editor.action.refactor.noneMessage.preferred", "No preferred refactorings available") : localize("editor.action.refactor.noneMessage", "No refactorings available"), {
      include: CodeActionKind.Refactor.contains(args.kind) ? args.kind : CodeActionKind.None,
      onlyIncludePreferredActions: args.preferred
    }, args.apply);
  }
}
class SourceAction extends EditorAction {
  constructor() {
    super({
      id: sourceActionCommandId,
      label: localize("source.label", "Source Action..."),
      alias: "Source Action...",
      precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider),
      contextMenuOpts: {
        group: "1_modification",
        order: 2.1,
        when: ContextKeyExpr.and(EditorContextKeys.writable, contextKeyForSupportedActions(CodeActionKind.Source))
      },
      description: {
        description: "Source Action...",
        args: [{ name: "args", schema: argsSchema }]
      }
    });
  }
  run(_accessor, editor, userArgs) {
    const args = CodeActionCommandArgs.fromUser(userArgs, {
      kind: CodeActionKind.Source,
      apply: "never"
      /* Never */
    });
    return triggerCodeActionsForEditorSelection(editor, typeof (userArgs === null || userArgs === void 0 ? void 0 : userArgs.kind) === "string" ? args.preferred ? localize("editor.action.source.noneMessage.preferred.kind", "No preferred source actions for '{0}' available", userArgs.kind) : localize("editor.action.source.noneMessage.kind", "No source actions for '{0}' available", userArgs.kind) : args.preferred ? localize("editor.action.source.noneMessage.preferred", "No preferred source actions available") : localize("editor.action.source.noneMessage", "No source actions available"), {
      include: CodeActionKind.Source.contains(args.kind) ? args.kind : CodeActionKind.None,
      includeSourceActions: true,
      onlyIncludePreferredActions: args.preferred
    }, args.apply);
  }
}
class OrganizeImportsAction extends EditorAction {
  constructor() {
    super({
      id: organizeImportsCommandId,
      label: localize("organizeImports.label", "Organize Imports"),
      alias: "Organize Imports",
      precondition: ContextKeyExpr.and(EditorContextKeys.writable, contextKeyForSupportedActions(CodeActionKind.SourceOrganizeImports)),
      kbOpts: {
        kbExpr: EditorContextKeys.editorTextFocus,
        primary: 1024 | 512 | 45,
        weight: 100
        /* EditorContrib */
      }
    });
  }
  run(_accessor, editor) {
    return triggerCodeActionsForEditorSelection(
      editor,
      localize("editor.action.organize.noneMessage", "No organize imports action available"),
      { include: CodeActionKind.SourceOrganizeImports, includeSourceActions: true },
      "ifSingle"
      /* IfSingle */
    );
  }
}
class FixAllAction extends EditorAction {
  constructor() {
    super({
      id: fixAllCommandId,
      label: localize("fixAll.label", "Fix All"),
      alias: "Fix All",
      precondition: ContextKeyExpr.and(EditorContextKeys.writable, contextKeyForSupportedActions(CodeActionKind.SourceFixAll))
    });
  }
  run(_accessor, editor) {
    return triggerCodeActionsForEditorSelection(
      editor,
      localize("fixAll.noneMessage", "No fix all action available"),
      { include: CodeActionKind.SourceFixAll, includeSourceActions: true },
      "ifSingle"
      /* IfSingle */
    );
  }
}
class AutoFixAction extends EditorAction {
  constructor() {
    super({
      id: AutoFixAction.Id,
      label: localize("autoFix.label", "Auto Fix..."),
      alias: "Auto Fix...",
      precondition: ContextKeyExpr.and(EditorContextKeys.writable, contextKeyForSupportedActions(CodeActionKind.QuickFix)),
      kbOpts: {
        kbExpr: EditorContextKeys.editorTextFocus,
        primary: 512 | 1024 | 84,
        mac: {
          primary: 2048 | 512 | 84
          /* Period */
        },
        weight: 100
        /* EditorContrib */
      }
    });
  }
  run(_accessor, editor) {
    return triggerCodeActionsForEditorSelection(
      editor,
      localize("editor.action.autoFix.noneMessage", "No auto fixes available"),
      {
        include: CodeActionKind.QuickFix,
        onlyIncludePreferredActions: true
      },
      "ifSingle"
      /* IfSingle */
    );
  }
}
AutoFixAction.Id = "editor.action.autoFix";
export {
  AutoFixAction,
  CodeActionCommand,
  FixAllAction,
  OrganizeImportsAction,
  QuickFixAction,
  QuickFixController,
  RefactorAction,
  SourceAction,
  applyCodeAction
};
