import type Point from "../../geometry/Point.js";
import type SpatialReference from "../../geometry/SpatialReference.js";
import type LOD from "./LOD.js";
import type { JSONSupport } from "../../core/JSONSupport.js";
import type { PointProperties } from "../../geometry/Point.js";
import type { LODProperties } from "./LOD.js";
import type { SpatialReferenceProperties } from "../../geometry/SpatialReference.js";

export interface TileInfoProperties extends Partial<Pick<TileInfo, "dpi" | "format" | "size">> {
  /** An array of levels of detail that define the tiling scheme. */
  lods?: LODProperties[];
  /** The tiling scheme origin. The upper left corner of the tiling scheme, in coordinates of the spatial reference of the source data. */
  origin?: PointProperties;
  /** The spatial reference of the tiling schema. */
  spatialReference?: SpatialReferenceProperties;
}

/** Image format of the cached tiles. */
export type Format = "png" | "png8" | "png24" | "png32" | "jpg" | "dib" | "tiff" | "emf" | "ps" | "pdf" | "gif" | "svg" | "svgz" | "mixed" | "lerc" | "lerc2d" | "raw" | "pbf";

/**
 * Defines the size, scales, and/or [SpatialReference](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-SpatialReference.html) used to generate a new TileInfo instance,
 * and is used with the [create()](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-support-TileInfo.html#create) method.
 */
export interface TileInfoCreateOptions {
  /**
   * The size of each tile in pixels.
   *
   * @default 256
   */
  size?: number;
  /**
   * The spatial reference
   * for the new TileInfo instance. If the spatial reference is not [SpatialReference.WGS84](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-SpatialReference.html#WGS84) nor [SpatialReference.WebMercator](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-SpatialReference.html#WebMercator),
   * the origin of the TileInfo is `0.0`.
   *
   * @default WebMercator
   */
  spatialReference?: SpatialReference;
  /**
   * An array of scale values to use for the TileInfo.
   * If none are specified, the scales from the [ArcGIS Online basemaps](https://www.arcgis.com/home/group.html?id=702026e41f6641fb85da88efe79dc166#overview) are used from level 0 through 24.
   *
   * @default The scales provided by ArcGIS Online basemaps
   */
  scales?: number[];
  /**
   * Total number of LODs to create.
   *
   * @default 24
   */
  numLODs?: number;
}

/**
 * Contains information about the tiling scheme for [TileLayers](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-TileLayer.html),
 * [ElevationLayers](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-ElevationLayer.html), [ImageryTileLayers](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-ImageryTileLayer.html),
 * [VectorTileLayers](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-VectorTileLayer.html), and [WebTileLayers](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-WebTileLayer.html).
 *
 * TileInfo defines properties such as tile format, the level of details (LOD) at which the cache has tiles, the size of the tiles in pixels, and the screen resolution
 * for which the tiles are intended to be most commonly displayed.
 *
 * @since 4.0
 */
export default class TileInfo extends JSONSupport {
  /**
   * A convenience method used to create a new TileInfo instance with preset properties like [lods](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-support-TileInfo.html#lods). Optionally, properties such as `size`, `scales[]`, and a `[SpatialReference](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-SpatialReference.html)` can also be set to calculate [lods](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-support-TileInfo.html#lods) for each `TileInfo`. This is useful in cases where the default amount of LODs provided are not sufficient. For example, if wanting to set the view's scale 1:1, additional LODs must be created. An example of setting this scale and creating additional LODs is provided in the example snippet below.
   *
   * @param options - An object that contains the size, scales, and/or [SpatialReference](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-SpatialReference.html) used to
   * compute the new TileInfo instance.
   * @returns A new TileInfo instance. The scales determine what [lods](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-support-TileInfo.html#lods) to create.
   * The DPI defaults to 96 and currently cannot be modified.
   * @see [MapView.constraints](https://developers.arcgis.com/javascript/latest/api-reference/esri-views-MapView.html#constraints)
   * @example
   * // This snippet shows how to create a TileInfo instance using the default
   * // settings and passing its resulting LODs to a MapView's constraints
   *
   * let view = new MapView({
   *   container: "viewDiv",
   *   map: map,
   *   constraints: {
   *     lods: TileInfo.create().lods
   *   }
   * });
   * @example
   * // This snippet shows how to set the MapView scale 1:1 while generating additional LODs for the MapView.constraints.
   * const spatialReference = new SpatialReference({
   *   wkid: 2154
   * });
   *
   * const center = new Point({
   *   x: 0,
   *   y: 0,
   *   spatialReference
   * });
   *
   * // Create LODs from level 0 to 31
   * const tileInfo = TileInfo.create({
   *   spatialReference,
   *   numLODs: 32
   * });
   *
   * const lods = tileInfo.lods;
   *
   * let view = new MapView({
   *   container: "viewDiv",
   *   map,
   *   scale: 1,
   *   center,
   *   spatialReference,
   *   constraints: {
   *     lods: lods,
   *     snapToZoom: false
   *   }
   * });
   */
  static create(options?: TileInfoCreateOptions): TileInfo;
  constructor(properties?: TileInfoProperties);
  /**
   * The dots per inch (DPI) of the tiling scheme.
   * If a DPI is chosen that does not match the resolution of the output device, the scale of the map tile will appear incorrect. The default value is 96.
   *
   * @default 96
   */
  accessor dpi: number;
  /** Image format of the cached tiles. */
  accessor format: Format;
  /**
   * Indicates if the tiling scheme supports wrap around.
   *
   * @since 4.5
   */
  get isWrappable(): boolean;
  /** An array of levels of detail that define the tiling scheme. */
  get lods(): LOD[];
  set lods(value: LODProperties[]);
  /** The tiling scheme origin. The upper left corner of the tiling scheme, in coordinates of the spatial reference of the source data. */
  get origin(): Point;
  set origin(value: PointProperties);
  /**
   * Size of tiles in pixels.
   *
   * @example
   * // sets the height and width of each tile to [ 256, 256 ]
   * tileInfo.size = 256;
   */
  accessor size: [
      number,
      number
  ];
  /** The spatial reference of the tiling schema. */
  get spatialReference(): SpatialReference;
  set spatialReference(value: SpatialReferenceProperties);
  /**
   * Utility method used to convert a scale value to its corresponding zoom value.
   *
   * @param scale - The scale value to convert.
   * @returns The returned zoom value.
   * @example
   * // get the zoom value for the vector tile layer at the given scale
   * // then set the view.zoom to match layer's zoom level.
   * view.when(function(){
   *   view.zoom = layer.tileInfo.scaleToZoom(9027);
   * });
   */
  scaleToZoom(scale: number): number;
  /**
   * Utility method used to convert a zoom value to its corresponding scale value.
   *
   * @param zoom - The zoom value to convert.
   * @returns The returned scale value.
   * @example
   * // get the scale value for the vector tile layer at the view zoom level
   * // then set the view.scale to match layer's scale.
   * view.when(function(){
   *   view.scale = vectorLayer.tileInfo.zoomToScale(view.zoom);
   * });
   */
  zoomToScale(zoom: number): number;
}