import type Extent from "../../geometry/Extent.js";
import type Multipoint from "../../geometry/Multipoint.js";
import type Point from "../../geometry/Point.js";
import type Polyline from "../../geometry/Polyline.js";
import type SpatialReference from "../../geometry/SpatialReference.js";
import type { EventedAccessor } from "../../core/Evented.js";

/**
 * A cache of elevation values created from an elevation service or the [GroundView](https://developers.arcgis.com/javascript/latest/references/core/views/GroundView/)
 * used for synchronously querying elevation information for geometries.
 * This class does not have a constructor. You can create an instance of this class by using
 * [ElevationLayer.createElevationSampler()](https://developers.arcgis.com/javascript/latest/references/core/layers/ElevationLayer/#createElevationSampler)
 * or [Ground.createElevationSampler()](https://developers.arcgis.com/javascript/latest/references/core/Ground/#createElevationSampler) methods.
 * The elevation sampler created from the [Ground](https://developers.arcgis.com/javascript/latest/references/core/Ground/) will sample data from the first elevation layer that has data available.
 * To control the layer used for elevation sampling and the sampling resolution, use
 * [ElevationLayer.createElevationSampler()](https://developers.arcgis.com/javascript/latest/references/core/layers/ElevationLayer/#createElevationSampler).
 *
 * ```js
 * map.ground.load()
 *   .then(function() {
 *     // create an elevation sampler from a given extent
 *     return view.map.ground.createElevationSampler(extent);
 *   })
 *   .then(function(elevationSampler) {
 *     // use the elevation sampler to get z-values for a point, multipoint or polyline geometry
 *     let zEnrichedGeometry = elevationSampler.queryElevation(geometry);
 *   });
 * ```
 *
 * An instance of this class is also available in [GroundView.elevationSampler](https://developers.arcgis.com/javascript/latest/references/core/views/GroundView/#elevationSampler).
 * This can be used when the elevation values need to reflect the elevation currently displayed in the view.
 *
 * ```js
 * let elevationSampler = view.groundView.elevationSampler;
 * // listen for elevation changes in the view
 * elevationSampler.on('changed', function() {
 *   // enrich geometry with z-values from the elevation displayed in the view
 *   let zEnrichedGeometry = elevationSampler.queryElevation(point);
 * });
 * ```
 *
 * @since 4.7
 * @see [ElevationLayer.createElevationSampler()](https://developers.arcgis.com/javascript/latest/references/core/layers/ElevationLayer/#createElevationSampler)
 * @see [Ground.createElevationSampler()](https://developers.arcgis.com/javascript/latest/references/core/Ground/#createElevationSampler)
 * @see [GroundView.elevationSampler](https://developers.arcgis.com/javascript/latest/references/core/views/GroundView/#elevationSampler)
 */
export default abstract class ElevationSampler extends EventedAccessor {
  /**
   * @deprecated
   * Do not directly reference this property.
   * Use EventNames and EventTypes helpers from \@arcgis/core/Evented
   */
  "@eventTypes": ElevationSamplerEvents;
  /** The minimum and maximum resolution of the data in the sampler. */
  abstract readonly demResolution: ElevationSamplerDemResolutionRange;
  /**
   * The extent within which the sampler can be queried.
   *
   * @since 4.9
   */
  abstract readonly extent?: Extent | null;
  /**
   * The value that is used to represent areas where there is no data available.
   *
   * @since 4.9
   */
  abstract readonly noDataValue?: number | null;
  /**
   * The spatial reference of the sampler.
   *
   * @since 4.24
   */
  abstract readonly spatialReference: SpatialReference;
  /**
   * Get elevation for a coordinate specified in the spatial reference of the sampler. This is typically faster
   * than [queryElevation()](https://developers.arcgis.com/javascript/latest/references/core/layers/support/ElevationSampler/#queryElevation) when getting elevation for many
   * coordinates that are guaranteed to be in the spatial reference of the sampler. If the coordinate is outside
   * of the elevation sampler extent, then the samplers [noDataValue](https://developers.arcgis.com/javascript/latest/references/core/layers/support/ElevationSampler/#noDataValue)
   * will be returned.
   *
   * @param x - The x coordinate.
   * @param y - The y coordinate.
   * @returns the elevation at the provided location. If no data could be sampled at the location, then the
   *   samplers [noDataValue](https://developers.arcgis.com/javascript/latest/references/core/layers/support/ElevationSampler/#noDataValue) will be returned.
   * @since 4.24
   */
  abstract elevationAt(x: number, y: number): number;
  /** @param geometry */
  queryElevation(geometry: Point): Point | null | undefined;
  /** @param geometry */
  queryElevation(geometry: Multipoint): Multipoint | null | undefined;
  /** @param geometry */
  queryElevation(geometry: Polyline): Polyline | null | undefined;
  /**
   * Query elevation for a [Point](https://developers.arcgis.com/javascript/latest/references/core/geometry/Point/), [Polyline](https://developers.arcgis.com/javascript/latest/references/core/geometry/Polyline/) or
   * [Multipoint](https://developers.arcgis.com/javascript/latest/references/core/geometry/Multipoint/) geometry. A query will return a new geometry
   * for which the z-values for each coordinate in the geometry are obtained from the elevation
   * sampler. If the geometry used for the query is outside of the elevation sampler extent,
   * then the returned geometry has the samplers [noDataValue](https://developers.arcgis.com/javascript/latest/references/core/layers/support/ElevationSampler/#noDataValue)
   * as z-values.
   *
   * @param geometry - The geometry to use for sampling elevation data.
   * @returns The sampled geometry.
   */
  queryElevation(geometry: Point | Polyline | Multipoint): Point | Polyline | Multipoint | null | undefined;
}

export interface ElevationSamplerEvents {
  /**
   * Fires when the data in the sampler has changed. This event is only relevant for dynamic elevation samplers
   * such as the elevation sampler on the [GroundView](https://developers.arcgis.com/javascript/latest/references/core/views/GroundView/).
   *
   * @example
   * view.groundView.elevationSampler.on("changed", function(evt) {
   *  console.log("elevation has changed");
   * });
   */
  changed: Record<never, never>;
}

export interface ElevationSamplerDemResolutionRange {
  /** The minimum resolution. */
  min: number;
  /** The maximum resolution. */
  max: number;
}