import type Collection from "../../core/Collection.js";
import type Point from "../../geometry/Point.js";
import type { ScreenPoint } from "../../core/types.js";
import type { Plugin, PluginConfiguration } from "./support/types.js";
import type { InteractiveToolBase } from "../interactive/InteractiveToolBase.js";
import type { SupportedEditGeometry } from "../interactive/editGeometry/interfaces.js";

/** @internal */
export interface DrawToolProperties extends Partial<Pick<DrawTool, "defaultZ" | "hasZ" | "lastScreenPosition">> {}

/**
 * `DrawTool` implements geometry creation workflows by orchestrating one or more
 *  plugins, which may be built-in or user provided. `DrawTool` provides common
 * resources and utilities to enable the creation of robust, accessible,
 * fully-featured, high-performance plugins.
 *
 * Plugins enable the development of rich desktop-class editing experiences
 * through composition of functionality. For example, we ship a `PolygonPlugin`
 * that implements key polygon behaviors (closing, snapping to closing vertex,
 * visualization); separate plugins enable creating vertices and edges.
 * Because of the separation, it is easy for us to add new plugins/editing
 * experiences; eventually, developer customers will also be able to contribute
 * new editing experiences.
 *
 * `DrawTool` does not directly manage UX; it is expected that most developers
 * will use `SketchViewModel` and `arcgis-sketch` to provide a complete
 * drawing experience.
 *
 * `DrawTool` implements the `IInteractiveTool` interface to work with the
 * view's `ToolViewManager` and related APIs like `view.addAndActivateTool`.
 *
 * `DrawTool` uses a variety of internal components to implement various
 * aspects of the drawing system. Key aspects that have been separated into
 * standalone components include:
 *
 * - cursor/manipulator ("interactive handle") management
 * - geometry measurement (which can be used to implement tooltips)
 * - tooltip field management
 * - undo/redo support and geometry manipulation (edit session)
 * - state toggle tracking (e.g. for states like `drawAtFixedElevation`
 *   that transcend a single plugin)
 * - plugin lifecycle (i.e. start/complete/cancel/etc) management
 * - elevation/z value handling.
 * - rendering visuals to represent both the drawn geometry and interactive UI
 *   elements, like vertices and manipulators.
 *
 * As of 5.0, DrawTool is 2D-only, but DrawTool is designed to support both
 * 2D and 3D.
 *
 * @internal
 */
export class DrawTool extends InteractiveToolBase {
  /** @internal */
  constructor(properties: DrawToolProperties);
  /** @internal */
  get canRedo(): boolean;
  /** @internal */
  get canUndo(): boolean;
  /**
   * @default 0
   * @internal
   */
  accessor defaultZ: number;
  /**
   * @default false
   * @internal
   */
  accessor hasZ: boolean;
  /** @internal */
  accessor lastScreenPosition: ScreenPoint | null | undefined;
  /**
   * The last plugin in the stack, including hidden plugins. This is the one that is
   * accepting primary input.
   *
   * @internal
   */
  get mostDownstreamPlugin(): Plugin | null | undefined;
  /**
   * The "root" plugin. This plugin is the first in the plugin stack and the one
   * that consumes the result of all downstream plugins and defines the final
   * shape of the geometry.
   *
   * @internal
   */
  get mostUpstreamPlugin(): Plugin | null | undefined;
  /** @internal */
  get pluginStack(): Collection<Plugin>;
  /** @internal */
  get positionOfLastUserInput(): Point | null | undefined;
  /** @internal */
  get updating(): boolean;
  /**
   * Gets the geometry that would be produced if the drawing was
   * completed without adding any further vertices (e.g. Enter is pressed).
   *
   * Equivalent to `unprocessedGeometry`, but without staged/in-progress vertex.
   *
   * @returns Geometry that would be produced on complete, without simplification.
   * @internal
   */
  getGeometryIfCompleted(): SupportedEditGeometry | null | undefined;
  /**
   * Replaces the leaf (most downstream plugin that isn't marked `hidden`) plugin
   * with plugins produced using the input configurations.
   *
   * @param configurations - Plugin configurations to start
   * @internal
   */
  replaceLeaf(configurations: PluginConfiguration[]): void;
}