import type Accessor from "@arcgis/core/core/Accessor.js";
import type PasteViewModel from "../PasteViewModel.js";
import type Graphic from "@arcgis/core/Graphic.js";
import type FeatureLayer from "@arcgis/core/layers/FeatureLayer.js";
import type SubtypeGroupLayer from "@arcgis/core/layers/SubtypeGroupLayer.js";
import type { Icon } from "@esri/calcite-components/components/calcite-icon";
import type { ApplySet } from "@arcgis/core/applications/Components/applySetUtils.js";
import type { GeometryUnion } from "@arcgis/core/geometry/types.js";

export interface PasteCommandProperties extends Partial<Pick<PasteCommand, "viewModel">> {}

/**
 * The types of supported paste operation
 * These maybe explicit ones, supported by the component, or user defined (as in string)
 *
 * @internal
 */
export type SupportedPasteCommand = "paste-append" | "paste-as" | "paste-merge" | "paste-subtract" | "paste" | (string & {});

/**
 * An interface which is used when a paste operation is run.
 * It allows the operation to cause the component to raise events or apply behaviour
 * in response to the operation running
 *
 * @internal
 */
export type PasteCommandApplyParameters = {
  closeAfterApply: () => void;
  onPasteError: (error: PasteApplyError) => void;
  onApply: (payload: {
      command: SupportedPasteCommand;
      applySet?: ApplySet;
  }) => Promise<{
      success: boolean;
      errorCode?: string;
      errorMessage?: string;
  }>;
};

/**
 * The Error type, that is raised when a paste operation fails
 *
 * @internal
 */
export type PasteApplyError = {
  errorCode: string;
  errorMessage: string;
  localizedErrorMessage?: keyof {
      componentLabel: string;
      noClipboardData: string;
      noPasteCommandsAvailable: string;
      pasteMultipleNotSupported: string;
      mixedGeometriesNotSupported: string;
      pasteAsMustHaveGeometry: string;
      clipboardContentsSingle: string;
      clipboardEmpty: string;
      clipboardContentsMany: string;
      clipboardContents: string;
      clipboardTooltip: string;
      pasteCommandChoices: string;
      pasteAsTitle: string;
      pasteMergeTitle: string;
      pasteTitle: string;
      cancel: string;
      close: string;
      tooManyCreateFeatures: string;
      tooManyCreateComplexFeatures: string;
      paste: string;
      pasteMany: string;
      attributesNotCopied: string;
      attributesSubtitle: string;
      preservethis: string;
      seeMergeOptions: string;
      selectionLabel: string;
      mergeOptionsTitle: string;
      features: string;
      mergeOptionsDesc: string;
      pasteWithAttributesLabel: string;
      preserved: string;
      pasteAppendTitle: string;
      pasteSubtractTitle: string;
      pasteAsDesc: string;
      pasteMergeDesc: string;
      pasteDesc: string;
      pasteAppendDesc: string;
      pasteSubtractDesc: string;
      choosefeature: string;
      next: string;
      updating: string;
      breadcrumb: string;
      back: string;
      noPasteItemsError: string;
      noChangeError: string;
      noSelectedError: string;
      noMatchingEditableLayers: string;
      deletesGeometryError: string;
      noGeometryError: string;
      unexpectedError: string;
      errorNoticeTitle: string;
      errorNoticeMessage: string;
      range: string;
      multipleFeaturesX: string;
  };
};

/** @internal */
export type PasteExecuteResult = {
  success: boolean;
  applySet?: ApplySet;
  userInputRequired: boolean;
};

/** @internal */
export class PasteCommand extends Accessor {
  constructor(properties?: PasteCommandProperties);
  /** A flag to indicate if the command is currently enabled */
  get commandEnabled(): boolean;
  /** An icon to represent the command */
  get icon(): Icon["icon"] | undefined;
  /** A unique ID for the command */
  get id(): SupportedPasteCommand;
  /** Flag to indicate this command will execute directly */
  get immediate(): boolean;
  /** Flag to indicate this command only exists on the Commands Page */
  get mustShowOnCommandPage(): boolean;
  accessor viewModel: PasteViewModel;
  /**
   * A reason why the command is disabled
   *
   * @param _systemStrings
   * @param _locale
   */
  commandDisabledReason(_systemStrings: {
      componentLabel: string;
      noClipboardData: string;
      noPasteCommandsAvailable: string;
      pasteMultipleNotSupported: string;
      mixedGeometriesNotSupported: string;
      pasteAsMustHaveGeometry: string;
      clipboardContentsSingle: string;
      clipboardEmpty: string;
      clipboardContentsMany: string;
      clipboardContents: string;
      clipboardTooltip: string;
      pasteCommandChoices: string;
      pasteAsTitle: string;
      pasteMergeTitle: string;
      pasteTitle: string;
      cancel: string;
      close: string;
      tooManyCreateFeatures: string;
      tooManyCreateComplexFeatures: string;
      paste: string;
      pasteMany: string;
      attributesNotCopied: string;
      attributesSubtitle: string;
      preservethis: string;
      seeMergeOptions: string;
      selectionLabel: string;
      mergeOptionsTitle: string;
      features: string;
      mergeOptionsDesc: string;
      pasteWithAttributesLabel: string;
      preserved: string;
      pasteAppendTitle: string;
      pasteSubtractTitle: string;
      pasteAsDesc: string;
      pasteMergeDesc: string;
      pasteDesc: string;
      pasteAppendDesc: string;
      pasteSubtractDesc: string;
      choosefeature: string;
      next: string;
      updating: string;
      breadcrumb: string;
      back: string;
      noPasteItemsError: string;
      noChangeError: string;
      noSelectedError: string;
      noMatchingEditableLayers: string;
      deletesGeometryError: string;
      noGeometryError: string;
      unexpectedError: string;
      errorNoticeTitle: string;
      errorNoticeMessage: string;
      range: string;
      multipleFeaturesX: string;
  }, _locale: string): string;
  createMergedClipboardGeom(): Promise<GeometryUnion | null>;
  /**
   * A description for the command
   *
   * @param _systemStrings
   * @param _locale
   */
  description(_systemStrings: {
      componentLabel: string;
      noClipboardData: string;
      noPasteCommandsAvailable: string;
      pasteMultipleNotSupported: string;
      mixedGeometriesNotSupported: string;
      pasteAsMustHaveGeometry: string;
      clipboardContentsSingle: string;
      clipboardEmpty: string;
      clipboardContentsMany: string;
      clipboardContents: string;
      clipboardTooltip: string;
      pasteCommandChoices: string;
      pasteAsTitle: string;
      pasteMergeTitle: string;
      pasteTitle: string;
      cancel: string;
      close: string;
      tooManyCreateFeatures: string;
      tooManyCreateComplexFeatures: string;
      paste: string;
      pasteMany: string;
      attributesNotCopied: string;
      attributesSubtitle: string;
      preservethis: string;
      seeMergeOptions: string;
      selectionLabel: string;
      mergeOptionsTitle: string;
      features: string;
      mergeOptionsDesc: string;
      pasteWithAttributesLabel: string;
      preserved: string;
      pasteAppendTitle: string;
      pasteSubtractTitle: string;
      pasteAsDesc: string;
      pasteMergeDesc: string;
      pasteDesc: string;
      pasteAppendDesc: string;
      pasteSubtractDesc: string;
      choosefeature: string;
      next: string;
      updating: string;
      breadcrumb: string;
      back: string;
      noPasteItemsError: string;
      noChangeError: string;
      noSelectedError: string;
      noMatchingEditableLayers: string;
      deletesGeometryError: string;
      noGeometryError: string;
      unexpectedError: string;
      errorNoticeTitle: string;
      errorNoticeMessage: string;
      range: string;
      multipleFeaturesX: string;
  }, _locale: string): string;
  /** Execute the command silently. Performs the logic of the paste command */
  execute(): Promise<PasteExecuteResult>;
  /**
   * Initiate the paste command
   *
   * @param _params
   * @param _options
   */
  initiate(_params: PasteCommandApplyParameters, _options?: { showFeatureForm?: boolean; }): Promise<void>;
  /**
   * A label for the command
   *
   * @param _systemStrings
   * @param _locale
   */
  label(_systemStrings: {
      componentLabel: string;
      noClipboardData: string;
      noPasteCommandsAvailable: string;
      pasteMultipleNotSupported: string;
      mixedGeometriesNotSupported: string;
      pasteAsMustHaveGeometry: string;
      clipboardContentsSingle: string;
      clipboardEmpty: string;
      clipboardContentsMany: string;
      clipboardContents: string;
      clipboardTooltip: string;
      pasteCommandChoices: string;
      pasteAsTitle: string;
      pasteMergeTitle: string;
      pasteTitle: string;
      cancel: string;
      close: string;
      tooManyCreateFeatures: string;
      tooManyCreateComplexFeatures: string;
      paste: string;
      pasteMany: string;
      attributesNotCopied: string;
      attributesSubtitle: string;
      preservethis: string;
      seeMergeOptions: string;
      selectionLabel: string;
      mergeOptionsTitle: string;
      features: string;
      mergeOptionsDesc: string;
      pasteWithAttributesLabel: string;
      preserved: string;
      pasteAppendTitle: string;
      pasteSubtractTitle: string;
      pasteAsDesc: string;
      pasteMergeDesc: string;
      pasteDesc: string;
      pasteAppendDesc: string;
      pasteSubtractDesc: string;
      choosefeature: string;
      next: string;
      updating: string;
      breadcrumb: string;
      back: string;
      noPasteItemsError: string;
      noChangeError: string;
      noSelectedError: string;
      noMatchingEditableLayers: string;
      deletesGeometryError: string;
      noGeometryError: string;
      unexpectedError: string;
      errorNoticeTitle: string;
      errorNoticeMessage: string;
      range: string;
      multipleFeaturesX: string;
  }, _locale: string): string;
  /**
   * Builds an ApplySet for the Paste, Paste-as and Paste-merge command
   *
   * @param activeTool
   */
  prepareCopy(activeTool: "paste-as" | "paste-merge" | "paste"): Promise<ApplySet | null>;
  /**
   * @param graphic
   * @param layer
   */
  removeGraphicIdentifierFields(graphic: Graphic, layer: FeatureLayer | SubtypeGroupLayer): void;
  /**
   * The logic for the paste, paste-as and paste-merge command
   *
   * @param params
   * @param tool
   * @param options
   */
  runPasteCommand(params: PasteCommandApplyParameters, tool: "paste-as" | "paste-merge" | "paste", options?: { showFeatureForm?: boolean; }): Promise<void>;
}