import type Geometry from "./Geometry.js";
import type { GeometryProperties } from "./Geometry.js";

export interface PointProperties extends GeometryProperties, Partial<Pick<Point, "latitude" | "longitude" | "m" | "x" | "y" | "z">> {
  /**
   * Indicates if the geometry has M values.
   *
   * > [!WARNING]
   * >
   * > **M-values** (measure) allow attribute values to be stored at the vertex
   * > of a point. A common usage for storing a measurement in the vertices
   * > along a linear feature are
   * > [linear referencing](https://pro.arcgis.com/en/pro-app/latest/help/data/linear-referencing/introduction-to-linear-referencing.htm)
   * > applications.
   */
  hasM?: boolean;
  /**
   * Indicates if the geometry has z-values (elevation).
   *
   * > [!WARNING]
   * >
   * > **Z-values** defined in a geographic or metric coordinate system are
   * > expressed in meters. However, in local scenes that use a
   * > projected coordinate system, vertical units are assumed to be the same as the
   * > horizontal units specified by the service.
   */
  hasZ?: boolean;
}

/**
 * A location defined by X, Y, and Z coordinates.
 *
 * > [!WARNING]
 * >
 * > **Z-values** defined in a geographic or metric coordinate system are
 * > expressed in meters. However, in local scenes that use a
 * > projected coordinate system, vertical units are assumed to be the same as the
 * > horizontal units specified by the service.
 *
 * @since 4.0
 * @see [Sample - Add graphics (MapView)](https://developers.arcgis.com/javascript/latest/sample-code/intro-graphics/)
 * @see [Sample - Add graphics (SceneView)](https://developers.arcgis.com/javascript/latest/sample-code/graphics-basic-3d/)
 * @see [Multipoint](https://developers.arcgis.com/javascript/latest/references/core/geometry/Multipoint/)
 */
export default class Point extends Geometry {
  constructor(properties?: PointProperties);
  /**
   * Indicates if the geometry has M values.
   *
   * > [!WARNING]
   * >
   * > **M-values** (measure) allow attribute values to be stored at the vertex
   * > of a point. A common usage for storing a measurement in the vertices
   * > along a linear feature are
   * > [linear referencing](https://pro.arcgis.com/en/pro-app/latest/help/data/linear-referencing/introduction-to-linear-referencing.htm)
   * > applications.
   */
  accessor hasM: boolean;
  /**
   * Indicates if the geometry has z-values (elevation).
   *
   * > [!WARNING]
   * >
   * > **Z-values** defined in a geographic or metric coordinate system are
   * > expressed in meters. However, in local scenes that use a
   * > projected coordinate system, vertical units are assumed to be the same as the
   * > horizontal units specified by the service.
   */
  accessor hasZ: boolean;
  /**
   * The latitude of the point. If the spatial reference is Web Mercator, the latitude will be given in WGS84. In any
   * geographic spatial reference, the latitude will equal the [y](https://developers.arcgis.com/javascript/latest/references/core/geometry/Point/#y) coordinate. In all other cases the latitude
   * will be null.
   */
  accessor latitude: number | null | undefined;
  /**
   * The longitude of the point. If the spatial reference is Web Mercator, the longitude will be given in WGS84. In any
   * geographic spatial reference, the longitude will equal the [x](https://developers.arcgis.com/javascript/latest/references/core/geometry/Point/#x) coordinate. In all other cases the longitude
   * will be null.
   */
  accessor longitude: number | null | undefined;
  /**
   * The m-coordinate of the point in map units.
   *
   * > [!WARNING]
   * >
   * > **M-values** (measure) allow attribute values to be stored at the vertex
   * > of a point. A common usage for storing a measurement in the vertices
   * > along a linear feature are
   * > [linear referencing](https://pro.arcgis.com/en/pro-app/latest/help/data/linear-referencing/introduction-to-linear-referencing.htm)
   * > applications.
   */
  accessor m: number | undefined;
  /** The string value representing the type of geometry. */
  get type(): "point";
  /**
   * The x-coordinate (easting) of the point in map units.
   *
   * @default 0
   */
  accessor x: number;
  /**
   * The y-coordinate (northing) of the point in map units.
   *
   * @default 0
   */
  accessor y: number;
  /**
   * The z-coordinate (or elevation) of the point in map units.
   *
   * > [!WARNING]
   * >
   * > **Z-values** defined in a geographic or metric coordinate system are
   * > expressed in meters. However, in local scenes that use a
   * > projected coordinate system, vertical units are assumed to be the same as the
   * > horizontal units specified by the service.
   */
  accessor z: number | undefined;
  /**
   * Creates a deep clone of Point object.
   *
   * @returns A new instance of a Point object equal to the object used to call `.clone()`.
   */
  clone(): Point;
  /**
   * Copies all values from another Point instance.
   *
   * @param other - The point to copy from.
   * @returns Returns this instance.
   */
  copy(other: Point): this;
  /**
   * Computes the Euclidean distance between this Point and a given Point. Points must have the same spatial reference.
   *
   * @param other - The point to compute the distance to.
   * @returns Returns the Euclidean distance between this Point and the other Point.
   */
  distance(other: Point): number;
  /**
   * Determines if the input point is equal to the point calling the function.
   *
   * @param point - The input point to test.
   * @returns Returns `true` if the X, Y, Z coordinates of the input point
   *                   along with its spatial reference and M value are exactly equal to those of the point calling `equals()`.
   */
  equals(point: Point | null | undefined): boolean;
  /**
   * Modifies the point geometry in-place by shifting the X-coordinate to within
   * +/- 180 span in map units. You should [clone()](https://developers.arcgis.com/javascript/latest/references/core/geometry/Point/#clone)
   * the point object before calling this method where appropriate.
   *
   * @returns Returns a point with a normalized x-value.
   */
  normalize(): this;
}