/**
 * Various utilities and convenience functions for working with [Mesh](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Mesh.html) objects.
 *
 * @since 4.7
 */
import type Ground from "../../Ground.js";
import type Extent from "../Extent.js";
import type Mesh from "../Mesh.js";
import type ElevationLayer from "../../layers/ElevationLayer.js";
import type ElevationSampler from "../../layers/support/ElevationSampler.js";
import type { AbortOptions } from "../../core/promiseUtils.js";
import type { MeshVertexSpaceUnion } from "../types.js";
import type { CreateElevationSamplerParameters, CreateFromElevationParameters } from "./meshUtils/types.js";

/**
 * Creates a mesh geometry by sampling elevation data from an elevation service on a regular grid.
 *
 * @param source - The source from which to query the elevation data.
 * @param extent - The extent from which to create the mesh.
 * @param options - Additional options.
 * @returns A promise that resolves to a mesh geometry representing the elevation data at the specified extent.
 * @example
 * // Create a mesh by sampling the ground
 * meshUtils.createFromElevation(map.ground, extent)
 *     .then(function(mesh) {
 *       // Do something with the mesh
 *     });
 *
 * // Create a mesh by sampling the ground surface currently in view
 * meshUtils.createFromElevation(view.groundView.elevationSampler, view.extent)
 *     .then(function(mesh) {
 *       // Do something with the mesh
 *     });
 */
export function createFromElevation(source: ElevationLayer | Ground | ElevationSampler, extent: Extent, options?: CreateFromElevationParameters): Promise<Mesh>;

/**
 * Creates an elevation sampler from a mesh. The sampler can be used to query elevation values
 * on the surface of the mesh. The elevation sampler uses a snapshot of the Mesh geometry and
 * will not update if the mesh changes after the sampler has been created.
 *
 * @param mesh - The mesh geometry used to create the elevation sampler.
 * @param options - Additional options.
 * @returns An elevation sampler.
 * @since 4.12
 * @see [Sample - Low poly terrain using mesh geometry](https://developers.arcgis.com/javascript/latest/sample-code/geometry-mesh-elevation/)
 */
export function createElevationSampler(mesh: Mesh, options?: CreateElevationSamplerParameters): Promise<ElevationSampler>;

/**
 * Merges multiple meshes into a single mesh. All mesh geometries
 * must be in the same spatial reference.
 *
 * @param geometries - One or more meshes.
 * @returns The merged mesh geometry.
 * @example const mergedMesh = meshUtils.merge([mesh1, mesh2]);
 */
export function merge(geometries: Mesh[]): Mesh | null | undefined;

/**
 * Converts a mesh to a new vertex space. Any [transform](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-support-MeshTransform.html) defined on
 * the mesh will be applied to the vertex attributes as part of the conversion.
 *
 * @param mesh - the mesh geometry to convert.
 * @param targetVertexSpace - the vertex space to convert to.
 * @param options - Additional options.
 * @returns The converted mesh.
 * @since 4.30
 * @example
 * // convert cartesian model data to a mesh with absolute coordinates in WebMercator
 * const converted = await convertVertexSpace(
 *   new Mesh({
 *     vertexSpace: new MeshLocalVertexSpace({ origin: location }),
 *     vertexAttributes,
 *     spatialReference: SpatialReference.WebMercator
 *   }),
 *   new MeshGeoreferencedVertexSpace()
 * );
 * @example
 * // convert a georeferenced WebMercator mesh to a mesh with a local tangent coordinate frame
 * // at the center of the mesh
 * const center = mesh.extent.center;
 * const origin = [center.x, center.y, center.z];
 * const converted = await convertVertexSpace(mesh, new MeshLocalVertexSpace({ origin }));
 * @example
 * // convert an existing mesh to absolute coordinates and place a graphic on the highest vertex
 * const converted = await convertVertexSpace(mesh, new MeshGeoreferencedVertexSpace());
 * const position = converted.vertexAttributes.position;
 *
 * const highestPoint = new Point({ x: 0, y: 0, z: 0, spatialReference: converted.spatialReference });
 *
 * for (let i = 0; i < position.length; i += 3) {
 *   if (position[i + 2] > highestPoint.z) {
 *     highestPoint.x = position[i];
 *     highestPoint.y = position[i + 1];
 *     highestPoint.z = position[i + 2];
 *   }
 * }
 *
 * view.graphics.add(new Graphic({ geometry: highestPoint }));
 */
export function convertVertexSpace(mesh: Mesh, targetVertexSpace: MeshVertexSpaceUnion, options?: AbortOptions): Promise<Mesh>;