import type BaseGeometry from "./Geometry.js";
import type Point from "./Point.js";
import type SpatialReference from "./SpatialReference.js";
import type { GeometryUnion } from "./types.js";
import type { SpatialReferenceProperties } from "./SpatialReference.js";
import type { GeometryProperties as BaseGeometryProperties } from "./Geometry.js";

export interface ExtentProperties extends BaseGeometryProperties, Partial<Pick<Extent, "mmax" | "mmin" | "xmax" | "xmin" | "ymax" | "ymin" | "zmax" | "zmin">> {
  /** The spatial reference of the geometry. */
  spatialReference?: SpatialReferenceProperties;
}

/**
 * The minimum and maximum X and Y coordinates of a bounding box. Extent is used
 * to describe the visible portion of a [MapView](https://developers.arcgis.com/javascript/latest/api-reference/esri-views-MapView.html).
 * When working in a [SceneView](https://developers.arcgis.com/javascript/latest/api-reference/esri-views-SceneView.html), [Camera](https://developers.arcgis.com/javascript/latest/api-reference/esri-Camera.html)
 * is used to define the visible part of the map within the view.
 *
 * @since 4.0
 * @see [MapView](https://developers.arcgis.com/javascript/latest/api-reference/esri-views-MapView.html)
 * @see [Camera](https://developers.arcgis.com/javascript/latest/api-reference/esri-Camera.html)
 */
export default class Extent extends BaseGeometry {
  constructor(properties?: ExtentProperties);
  /** The center point of the extent in map units. */
  get center(): Point;
  /** Indicates if the geometry has M values. */
  get 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.
   */
  get hasZ(): boolean;
  /** The height of the extent in map units (the distance between [ymin](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Extent.html#ymin) and [ymax](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Extent.html#ymax)). */
  get height(): number;
  /** The maximum possible `m` value in an extent envelope. */
  accessor mmax: number | undefined;
  /** The minimum possible `m` value of an extent envelope. */
  accessor mmin: number | undefined;
  /** The spatial reference of the geometry. */
  get spatialReference(): SpatialReference;
  set spatialReference(value: SpatialReferenceProperties);
  /** The geometry type. */
  get type(): "extent";
  /** The width of the extent in map units (the distance between [xmin](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Extent.html#xmin) and [xmax](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Extent.html#xmax)). */
  get width(): number;
  /**
   * The maximum X-coordinate of an extent envelope.
   *
   * @default 0
   */
  accessor xmax: number;
  /**
   * The minimum X-coordinate of an extent envelope.
   *
   * @default 0
   */
  accessor xmin: number;
  /**
   * The maximum Y-coordinate of an extent envelope.
   *
   * @default 0
   */
  accessor ymax: number;
  /**
   * The minimum Y-coordinate of an extent envelope.
   *
   * @default 0
   */
  accessor ymin: number;
  /**
   * The maximum possible `z`, or elevation, value in an extent envelope.
   *
   * > [!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 zmax: number | undefined;
  /**
   * The minimum possible `z`, or elevation, value of an extent envelope.
   *
   * > [!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 zmin: number | undefined;
  /**
   * Centers the extent to the specified [Point](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Point.html).
   * This method modifies the extent geometry in-place. You should [clone()](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Extent.html#clone)
   * the extent object before calling this method where appropriate.
   *
   * @param point - The point to center the extent.
   * @returns The new extent with `point` as the [center](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Extent.html#center).
   */
  centerAt(point: Point): this;
  /**
   * Creates a deep clone of Extent object.
   *
   * @returns A new instance of a Extent object equal to the object used to call `.clone()`.
   */
  clone(): Extent;
  /**
   * Checks if the input geometry is contained within the extent.
   *
   * @param geometry - Input geometry to test if it is contained within the extent.
   * @returns Returns `true` if the input geometry is contained within the extent.
   */
  contains(geometry: Point | Extent): boolean;
  /**
   * Indicates if the input extent is equal to the testing extent.
   *
   * @param extent - Input extent.
   * @returns Returns `true` if the input extent is equal to the extent that calls `equals()`.
   */
  equals(extent: Extent | null | undefined): boolean;
  /**
   * Expands the extent by the given factor. For example, a value of 1.5 will
   * expand the extent to be 50 percent larger than the original extent.
   * This method modifies the extent geometry in-place. You should [clone()](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Extent.html#clone)
   * the extent object before calling this method where appropriate.
   *
   * @param factor - The multiplier value.
   * @returns Returns the expanded extent.
   */
  expand(factor: number): this;
  /**
   * Shrinks the original extent to the intersection with the input extent.
   *
   * This method modifies the extent geometry in-place. You should [clone()](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Extent.html#clone) the extent object before calling
   * this method where appropriate. If the original extent and the input extent have no intersection, the extent is
   * not modified and null is returned.
   *
   * @param extent - The input extent to intersect.
   * @returns The intersection of the input Extent with the original Extent or null.
   */
  intersection(extent: Extent | null | undefined): this | null | undefined;
  /**
   * Tests to validate if the input geometry intersects the extent and returns a Boolean value.
   *
   * @param geometry - The geometry used to test the intersection. It can be a
   * [Point](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Point.html), [Polyline](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Polyline.html),
   * [Polygon](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Polygon.html), [Extent](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Extent.html) or
   * [Multipoint](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Multipoint.html).
   * @returns Returns `true`, if the input geometry intersects the extent.
   */
  intersects(geometry: GeometryUnion | null | undefined): boolean;
  /**
   * Returns an array with either one Extent that's been shifted to within +/- 180 or two Extents
   * if the original extent intersects the International Dateline.
   *
   * This method modifies the extent geometry in-place. You should [clone()](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Extent.html#clone)
   * the extent object before calling this method where appropriate.
   *
   * @returns The normalized Extent(s).
   */
  normalize(): Extent[];
  /**
   * Modifies the extent geometry in-place with X and Y offsets in map units.
   * You should [clone()](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Extent.html#clone)
   * the extent object before calling this method where appropriate.
   *
   * @param dx - The offset distance in map units for the X-coordinate.
   * @param dy - The offset distance in map units for the Y-coordinate.
   * @param dz - The offset distance in map units for the Z-coordinate.
   * @returns The offset Extent.
   */
  offset(dx: number, dy: number, dz?: number): this;
  /**
   * Expands the original extent to include the extent of the input Extent.
   * This method modifies the extent geometry in-place. You should [clone()](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Extent.html#clone)
   * the extent object before calling this method where appropriate.
   *
   * @param extent - The input extent to union.
   * @returns The union of the input Extent with the original Extent.
   */
  union(extent: Extent): this;
}