import type { ClonableMixin } from "../../core/Clonable.js";
import type { JSONSupport } from "../../core/JSONSupport.js";
import type { MeshTextureData } from "../types.js";

export interface MeshTextureProperties extends Partial<Pick<MeshTexture, "transparent" | "url" | "wrap">> {
  /**
   * A direct reference to the image or video data. The data can be an
   * [image element](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement),
   * [canvas element](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement),
   * [video element](https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement)
   * or [ImageData](https://developer.mozilla.org/en-US/docs/Web/API/ImageData).
   * If the data is set to a [video element](https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement),
   * the element needs to be visible in the DOM.
   * The data property is mutually exclusive with the url property, setting the data will clear the
   * url (if there is one).
   *
   * When cloning a MeshTexture, the data property is not deeply cloned but copied by reference instead.
   */
  data?: MeshTextureData | null;
}

/**
 * MeshTexture represents image data to be used for [MeshMaterial](https://developers.arcgis.com/javascript/latest/references/core/geometry/support/MeshMaterial/) or
 * [MeshMaterialMetallicRoughness](https://developers.arcgis.com/javascript/latest/references/core/geometry/support/MeshMaterialMetallicRoughness/).
 * It is mapped to the mesh by its uv vertex attributes. MeshTexture instances can be used
 * with the [MeshComponent.material](https://developers.arcgis.com/javascript/latest/references/core/geometry/support/MeshComponent/#material) property and they can be
 * set either as a [MeshMaterial.colorTexture](https://developers.arcgis.com/javascript/latest/references/core/geometry/support/MeshMaterial/#colorTexture)
 * or as [MeshMaterial.normalTexture](https://developers.arcgis.com/javascript/latest/references/core/geometry/support/MeshMaterial/#normalTexture).
 * Images can be referred to either by url or directly by data (
 * [HTMLImageElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement),
 * [HTMLCanvasElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement),
 * [HTMLVideoElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement)
 * or [ImageData](https://developer.mozilla.org/en-US/docs/Web/API/ImageData)).
 *
 * ```js
 * const meshColorByUrl = new MeshTexture({
 *   url: "./image.png"
 * });
 *
 * const mesh = Mesh.createBox(location, {
 *   material: {
 *     colorTexture: meshColorByUrl
 *   }
 * });
 *
 * const meshColorByCanvas = new MeshTexture({
 *   data: canvasElement
 * });
 *
 * const meshWithCanvasMaterial = Mesh.createBox(location, {
 *   material: {
 *     colorTexture: meshColorByCanvas
 *   }
 * });
 *
 * // Support for autocasting within a mesh material constructor
 * const meshWithAutocastMaterial = Mesh.createSphere(location, {
 *   material: {
 *     colorTexture: {
 *       url: "./image.png"
 *     }
 *   }
 * });
 *
 * // Mesh materials also support additional advanced autocasting types
 * // such as a Canvas element. In this case the canvas element will be
 * // available in the MeshTexture.data property.
 * const meshWithCanvasAutocastMaterial = Mesh.createSphere(location, {
 *   material: {
 *     colorTexture: canvasElement
 *   }
 * });
 *
 * // When using a video as a texture, you need to create a Video element
 * // and pass it in the MeshTexture.data property.
 * const video = document.createElement("video");
 * video.src = "./my-video.mp4";
 * video.crossOrigin = "anonymous";
 * video.autoplay = true;
 * video.muted = true;
 * // The video needs to be added to the DOM and be located in
 * // the viewport in order for it to play
 * document.body.appendChild(video);
 * video.style.position = "absolute";
 * video.style.top = 0;
 * // Hide the video element
 * video.style.height = 0;
 * video.style.visibility = "hidden";
 *
 * const meshWithVideoMaterial = Mesh.createPlane(location, {
 *   material: {
 *     colorTexture: { data: video }
 *   }
 * });
 * ```
 *
 * @since 4.11
 * @see [MeshMaterial](https://developers.arcgis.com/javascript/latest/references/core/geometry/support/MeshMaterial/)
 * @see [Mesh](https://developers.arcgis.com/javascript/latest/references/core/geometry/Mesh/)
 * @see [Sample - Working with 3d mesh primitives](https://developers.arcgis.com/javascript/latest/sample-code/geometry-mesh-primitives/)
 */
export default class MeshTexture extends MeshTextureSuperclass {
  constructor(properties?: MeshTextureProperties);
  /**
   * A direct reference to the image or video data. The data can be an
   * [image element](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement),
   * [canvas element](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement),
   * [video element](https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement)
   * or [ImageData](https://developer.mozilla.org/en-US/docs/Web/API/ImageData).
   * If the data is set to a [video element](https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement),
   * the element needs to be visible in the DOM.
   * The data property is mutually exclusive with the url property, setting the data will clear the
   * url (if there is one).
   *
   * When cloning a MeshTexture, the data property is not deeply cloned but copied by reference instead.
   */
  get data(): MeshTextureData | null;
  set data(value: MeshTextureData | null | undefined);
  /**
   * Indicates whether the image data should be interpreted as being semi-transparent.
   * The default value is automatically derived when the data property contains a canvas
   * element or an ImageData object. If instead a url to a .png file was provided, it is
   * assumed that transparency is present. In all other cases it defaults to `false`.
   */
  accessor transparent: boolean;
  /**
   * The url to the image resource. This can either be a remote url (absolute or relative) or a data url.
   * Video resources can only be loaded using the [data](https://developers.arcgis.com/javascript/latest/references/core/geometry/support/MeshTexture/#data) property.
   * The url property is mutually exclusive with the [data](https://developers.arcgis.com/javascript/latest/references/core/geometry/support/MeshTexture/#data) property, setting the url will clear the
   * data (if there is one).
   */
  accessor url: string | null | undefined;
  /**
   * Specifies how uv coordinates outside the [0, 1] range are handled. One of "repeat", "clamp" or "mirror".
   * Can also be specified separately for the two texture axes using an object:
   *
   * ```js
   * {
   *   vertical: "clamp",
   *   horizontal: "repeat"
   * }
   * ```
   *
   * @default "repeat"
   */
  accessor wrap: TextureWrapSeparate | MeshTextureWrap;
}
declare const MeshTextureSuperclass: typeof JSONSupport & typeof ClonableMixin

export type MeshTextureWrap = "repeat" | "clamp" | "mirror";

/** A separable wrap configuration for horizontal and vertical wrapping modes. */
export interface TextureWrapSeparate {
  /** Horizontal wrapping mode. */
  horizontal: MeshTextureWrap;
  /** Vertical wrapping mode. */
  vertical: MeshTextureWrap;
}