import type Graphic from "../Graphic.js";
import type Collection from "../core/Collection.js";
import type Extent from "../geometry/Extent.js";
import type SpatialReference from "../geometry/SpatialReference.js";
import type Layer from "./Layer.js";
import type TimeInfo from "./support/TimeInfo.js";
import type WMSSublayer from "./support/WMSSublayer.js";
import type TimeExtent from "../time/TimeExtent.js";
import type TimeInterval from "../time/TimeInterval.js";
import type { ReadonlyCollection, ReadonlyArrayOrCollection } from "../core/Collection.js";
import type { MultiOriginJSONSupportMixin } from "../core/MultiOriginJSONSupport.js";
import type { AbortOptions } from "../core/promiseUtils.js";
import type { LayerEvents, LayerProperties } from "./Layer.js";
import type { BlendLayer, BlendLayerProperties } from "./mixins/BlendLayer.js";
import type { OperationalLayer, OperationalLayerProperties } from "./mixins/OperationalLayer.js";
import type { PortalLayer, PortalLayerProperties } from "./mixins/PortalLayer.js";
import type { RefreshableLayer, RefreshableLayerEvents, RefreshableLayerProperties } from "./mixins/RefreshableLayer.js";
import type { ScaleRangeLayer, ScaleRangeLayerProperties } from "./mixins/ScaleRangeLayer.js";
import type { TemporalLayer, TemporalLayerProperties } from "./mixins/TemporalLayer.js";
import type { TimeInfoProperties } from "./support/TimeInfo.js";
import type { WMSDimension } from "./wms/types.js";
import type { TimeExtentProperties } from "../time/TimeExtent.js";
import type { TimeIntervalProperties } from "../time/TimeInterval.js";
import type { ExtentProperties } from "../geometry/Extent.js";
import type { SpatialReferenceProperties } from "../geometry/SpatialReference.js";
import type { WMSSublayerProperties } from "./support/WMSSublayer.js";

export interface WMSLayerProperties extends LayerProperties, PortalLayerProperties, OperationalLayerProperties, ScaleRangeLayerProperties, RefreshableLayerProperties, TemporalLayerProperties, BlendLayerProperties, Partial<Pick<WMSLayer, "copyright" | "customLayerParameters" | "customParameters" | "description" | "featureInfoFormat" | "featureInfoUrl" | "fetchFeatureInfoFunction" | "imageFormat" | "imageMaxHeight" | "imageMaxWidth" | "imageTransparency" | "legendEnabled" | "spatialReferences" | "url" | "version">> {
  /** All bounding boxes defined for the layer. */
  fullExtents?: ExtentProperties[] | null;
  /** The spatial reference of the layer. */
  spatialReference?: SpatialReferenceProperties;
  /**
   * A subset of the layer's [WMSSublayer](https://developers.arcgis.com/javascript/latest/references/core/layers/support/WMSSublayer/)s that will be displayed.
   *
   * If you set the sublayers property at the time of the layer's initialization, this will override the sublayer information from the service.
   * For example, if you define a sublayer at layer initialization based on the name, as shown in the snippet below, other sublayer properties,
   * such as the `legendUrl`, `minScale`, and `maxScale`, will be set to the default values from the API, not the values defined in the service.
   *
   * ```js
   * const wmsLayer = new WMSLayer({
   *   url: "url-to-wms-service",
   *   sublayers: [{
   *     name: "sublayer-name"
   *   }]
   * });
   * ```
   *
   * Alternatively, in order to retain the service's definition for each sublayer, update the
   * `sublayers` property after loading the layer as demonstrated below.
   *
   * ```js
   * const wmsLayer = new WMSLayer({
   *   url: "url-to-wms-service"
   * });
   * await wmsLayer.load();
   * const sublayer = wmsLayer.findSublayerByName("sublayer-name");
   * if (sublayer) {
   *   wmsLayer.sublayers = [sublayer];
   * }
   * ```
   */
  sublayers?: ReadonlyArrayOrCollection<WMSSublayerProperties>;
  /**
   * The layer's time extent. When the layer's [useViewTime](https://developers.arcgis.com/javascript/latest/references/core/layers/WMSLayer/#useViewTime) is `false`, the layer
   * instructs the view to show data from the layer based on this time extent.
   * If the `useViewTime` is `true`, and both layer and view time extents are set, then features that fall within
   * the intersection of the view and layer time extents will be displayed.
   * For example, if the layer's time extent is set to display features between 1970 and 1975 and
   * the view has a time extent set to 1972-1980, the effective time on the feature layer will be 1972-1975.
   *
   * @since 4.17
   * @example
   * if (!layer.useViewTime) {
   *   if (layer.timeExtent) {
   *     console.log("Current timeExtent:", layer.timeExtent.start, " - ", layer.timeExtent.end}
   *   } else {
   *     console.log("The layer will display data within the view's timeExtent.");
   *     console.log("Current view.timeExtent:", view.timeExtent.start, " - ", view.timeExtent.end}
   *   }
   * }
   * @example
   * // set the timeExtent on the layer and useViewTime false
   * // In this case, the layer will honor its timeExtent and ignore
   * // the view's timeExtent
   * const layer = new WMSLayer({
   *   url: "https://geo.weather.gc.ca/geomet",
   *   timeExtent: {
   *     start: new Date(Date.UTC(2020, 8, 12)),
   *     end:  new Date(Date.UTC(2020, 8, 14)),
   *   },
   *   useViewTime: false
   * });
   * @example
   * // timeExtent is set on the layer and the view
   * // In this case, the layer will display features that fall
   * // within the intersection of view and layer time extents
   * // features within Jan 1, 1976 - Jan 1, 1981 will be displayed
   * const view = new MapView({
   *   timeExtent: {
   *     start: new Date(1976, 0, 1),
   *     end: new Date(2002, 0, 1)
   *   }
   * });
   * const layer = new WMSLayer({
   *   url: myUrl,
   *   timeExtent: {
   *     start: new Date(1974, 0, 1),
   *     end: new Date(1981, 0, 1)
   *   }
   * });
   * @example
   * if (!layer.useViewTime) {
   *   if (layer.timeExtent) {
   *     console.log("Current timeExtent:", layer.timeExtent.start, " - ", layer.timeExtent.end}
   *   } else {
   *     console.log("The layer will display data within the view's timeExtent.");
   *     console.log("Current view.timeExtent:", view.timeExtent.start, " - ", view.timeExtent.end}
   *   }
   * }
   * @example
   * // set the timeExtent on the layer and useViewTime false
   * // In this case, the layer will honor its timeExtent and ignore
   * // the view's timeExtent
   * const layer = new ImageryLayer({
   *   url: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/ScientificData/SeaTemperature/ImageServer",
   *   timeExtent: {
   *     start: new Date(2014, 4, 18),
   *     end: new Date(2014, 4, 19)
   *   },
   *   useViewTime: false
   * });
   * @example
   * // timeExtent is set on the layer and the view
   * // In this case, the layer will display features that fall
   * // within the intersection of view and layer time extents
   * // features within Jan 1, 1976 - Jan 1, 1981 will be displayed
   * const view = new MapView({
   *   timeExtent: {
   *     start: new Date(1976, 0, 1),
   *     end: new Date(2002, 0, 1)
   *   }
   * });
   * const layer = new FeatureLayer({
   *   url: myUrl,
   *   timeExtent: {
   *     start: new Date(1974, 0, 1),
   *     end: new Date(1981, 0, 1)
   *   }
   * });
   */
  timeExtent?: TimeExtentProperties | null;
  /**
   * TimeInfo provides information such as date fields that store
   * [start](https://developers.arcgis.com/javascript/latest/references/core/layers/support/TimeInfo/#startField)
   * and [end](https://developers.arcgis.com/javascript/latest/references/core/layers/support/TimeInfo/#endField) time
   * for each feature and the [TimeInfo.fullTimeExtent](https://developers.arcgis.com/javascript/latest/references/core/layers/support/TimeInfo/#fullTimeExtent)
   * for the layer. The `timeInfo` property is automatically set at layer initialization if the layer has one or more time dimensions.
   * The [TimeInfo.fullTimeExtent](https://developers.arcgis.com/javascript/latest/references/core/layers/support/TimeInfo/#fullTimeExtent) for `timeInfo` is
   * automatically set to the union of all time dimension extents.
   * The timeInfo parameters cannot be changed after the layer is [loaded](https://developers.arcgis.com/javascript/latest/references/core/layers/WMSLayer/#load).
   *
   * @since 4.17
   * @example
   * // create geojson layer from usgs earthquakes geojson feed
   * const geojsonLayer = new GeoJSONLayer({
   *   url: "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_month.geojson",
   *   copyright: "USGS Earthquakes",
   *   fields: [
   *     { "name": "mag", "type": "double" },
   *     { "name": "place", "type": "string" },
   *     { "name": "time", "type": "date" }, // date field
   *     { "name": "depth", "type": "double" }
   *   ],
   *   // timeInfo can be used to do temporal queries
   *   // set the startField and endField.
   *   // timeExtent is automatically calculated from the
   *   // the start and end date fields
   *   // The date values must be in milliseconds number from the UNIX epoch specified in UTC.
   *   timeInfo: {
   *     startField: "time"
   *   }
   * });
   */
  timeInfo?: TimeInfoProperties | null;
  /**
   * A temporary offset of the time data based on a certain [TimeInterval](https://developers.arcgis.com/javascript/latest/references/core/time/TimeInterval/). This allows
   * users to overlay features from two or more time-aware layers with different time extents.
   * For example, if a layer has data recorded for the year 1970, an offset value of 2 years would temporarily shift the data to
   * 1972. You can then overlay this data with data recorded in 1972.
   * A time offset can be used for display purposes only. The query and selection are not affected by the offset.
   *
   * @since 4.17
   * @example
   * // Offset a CSV Layer containing hurricanes from 2015 so that they appear in 2019 (+4 years).
   * let layer = new CSVLayer({
   *   url: `hurricanes-and-storms-2015.csv`,
   *   timeOffset: {
   *     value: 4,
   *     unit: "years"
   *   },
   *   timeInfo: {
   *     startField: "ISO_time"
   *   },
   *   renderer: {
   *     type: "simple",
   *     symbol: {
   *       type: "simple-marker",
   *       size: 6,
   *       color: "red",
   *       outline: {
   *         width: 0.5,
   *         color: "black"
   *       }
   *     }
   *   }
   * });
   * @example
   * // Offset a CSV Layer containing hurricanes from 2015 so that they appear in 2019 (+4 years).
   * let layer = new CSVLayer({
   *   url: `hurricanes-and-storms-2015.csv`,
   *   timeOffset: {
   *     value: 4,
   *     unit: "years"
   *   },
   *   timeInfo: {
   *     startField: "ISO_time"
   *   },
   *   renderer: {
   *     type: "simple",
   *     symbol: {
   *       type: "simple-marker",
   *       size: 6,
   *       color: "red",
   *       outline: {
   *         width: 0.5,
   *         color: "black"
   *       }
   *     }
   *   }
   * });
   */
  timeOffset?: TimeIntervalProperties | null;
  /**
   * The title of the layer used to identify it in places such as the [Legend](https://developers.arcgis.com/javascript/latest/references/map-components/components/arcgis-legend/)
   * and [LayerList](https://developers.arcgis.com/javascript/latest/references/core/widgets/LayerList/).
   *
   * When the layer is loaded from a portal item, the title of the portal item will be used.
   * If a layer is loaded as part of a webmap or a webscene, then the title of the layer as stored in the webmap/webscene will be used.
   */
  title?: string | null;
  /**
   * Determines if the layer will update its temporal data based on the view's
   * [View.timeExtent](https://developers.arcgis.com/javascript/latest/references/core/views/View/#timeExtent). When `false`, the layer will display its temporal
   * data based on the layer's [timeExtent](https://developers.arcgis.com/javascript/latest/references/core/layers/WMSLayer/#timeExtent), regardless of changes to the view.
   * If both view and layer time extents are set while this property is `true`, then the features that fall within
   * the intersection of the view and layer time extents will be displayed.
   * For example, if a layer's time extent is set to display features between 1970 and 1975 and
   * the view has a time extent set to 1972-1980, the effective time on the feature layer will be 1972-1975.
   *
   * @default true
   * @since 4.17
   * @example
   * if (wmsLayer.useViewTime) {
   *   console.log("Displaying data between:", view.timeExtent.start, " - ", view.timeExtent.end);
   * }
   * @example
   * if (featureLayer.useViewTime) {
   *   console.log("Displaying data between:", view.timeExtent.start, " - ", view.timeExtent.end);
   * }
   */
  useViewTime?: boolean;
}

export type WMSLayerFormatType = "image/jpeg" | "image/bmp" | "image/gif" | "image/svg+xml" | "image/png";

/**
 * Function definition for the [fetchFeatureInfoFunction](https://developers.arcgis.com/javascript/latest/references/core/layers/WMSLayer/#fetchFeatureInfoFunction) property.
 *
 * @param query - An object containing the query parameter names and values.
 * @returns Resolves to an array of Graphics.
 */
export type FetchFeatureInfoFunction = (query: Record<string, any>) => Promise<Graphic[]>;

export type FeatureInfoFormat = "text/html" | "text/plain";

export interface WMSLayerEvents extends RefreshableLayerEvents, LayerEvents {}

/**
 * The WMSLayer is used to create layers based on OGC Web Map Services (WMS).
 * Requests must be same-origin or require [CORS](https://developers.arcgis.com/javascript/latest/cors/) to be enabled on the server.
 *
 * @since 4.4
 * @see [Sample - WMSLayer](https://developers.arcgis.com/javascript/latest/sample-code/layers-wms/)
 * @see [OpenGIS Web Map Service Implementation Specification (pdf)](https://portal.ogc.org/files/?artifact_id=14416)
 */
export default class WMSLayer extends WMSLayerSuperclass {
  /**
   * @deprecated
   * Do not directly reference this property.
   * Use EventNames and EventTypes helpers from \@arcgis/core/Evented
   */
  "@eventTypes": WMSLayerEvents;
  /**
   * @example
   * // Typical usage
   * const layer = new WMSLayer({
   *   url: // url to the service
   * });
   * await layer.load();
   * // filter by a given sublayer
   * const sublayer = layer.findSublayerByName("My Sublayer");
   * if (sublayer) {
   *   layer.sublayers = [sublayer];
   * }
   * map.add(layer);
   */
  constructor(properties?: WMSLayerProperties);
  /**
   * A flattened collection of all [WMSSublayer](https://developers.arcgis.com/javascript/latest/references/core/layers/support/WMSSublayer/)s based on the [sublayers](https://developers.arcgis.com/javascript/latest/references/core/layers/WMSLayer/#sublayers) property.
   *
   * @since 4.17
   * @example
   * // Print the names of all sublayers used for rendering.
   * const layer = new WMSLayer({
   *   url: "https://geo.weather.gc.ca/geomet"
   * });
   * layer.load().then(() => {
   *   const names = layer.allSublayers
   *                      .filter((sublayer) => !sublayer.sublayers) // Non-grouping layers will not have any "sublayers".
   *                      .map((sublayer) => sublayer.name);
   *   console.log("Names of all child sublayers", names.join());
   * });
   */
  get allSublayers(): ReadonlyCollection<WMSSublayer>;
  /**
   * Copyright information for the WMS service.
   * This defaults to the value of the AccessConstraints property from the GetCapabilities request.
   */
  accessor copyright: string | null | undefined;
  /**
   * Use this to append different custom parameters to the WMS map requests.
   * The custom layer parameters are applied to GetMap and GetFeatureInfo.
   */
  accessor customLayerParameters: Record<string, string> | null | undefined;
  /**
   * Use this to append custom parameters to all WMS requests.
   * The custom parameters are applied to GetCapabilities, GetMap and GetFeatureInfo.
   * For example, if an access key is required, the key can be configured as a custom parameter.
   * The layer's refresh() method needs to be called if the customParameters are updated at runtime.
   */
  accessor customParameters: Record<string, string> | null | undefined;
  /**
   * Description for the WMS layer.
   * This defaults to the value of the Abstract property from the WMS GetCapabilities request.
   */
  accessor description: string | null | undefined;
  /**
   * An array of time, elevation and other dimensions for the root layer.
   * Information from a [TimeDimension](https://developers.arcgis.com/javascript/latest/references/core/layers/wms/types/#TimeDimension) can be used to update [View.timeExtent](https://developers.arcgis.com/javascript/latest/references/core/views/View/#timeExtent),
   * [timeExtent](https://developers.arcgis.com/javascript/latest/references/core/layers/WMSLayer/#timeExtent), or to configure a [TimeSlider](https://developers.arcgis.com/javascript/latest/references/core/widgets/TimeSlider/) widget.
   *
   * A WMSLayer or [WMSSublayer](https://developers.arcgis.com/javascript/latest/references/core/layers/support/WMSSublayer/) can only have one time dimension. The following example shows how to find the
   * time dimension (if any) for the base layer.
   *
   * ```js
   * const layer = new WMSLayer({
   *   url: "https://public-wms.met.no/verportal/verportal.map?request=GetCapabilities&service=WMS&version=1.3.0"
   * });
   * await layer.load();
   * const timeDimension = layer.dimensions.find((dimension) => dimension.name === "time");
   * ```
   *
   * Data can exist at specific times or time ranges. We can access this information from the `extent` property of the
   * [TimeDimension](https://developers.arcgis.com/javascript/latest/references/core/layers/wms/types/#TimeDimension) as either an array of discrete dates or [DimensionInterval](https://developers.arcgis.com/javascript/latest/references/core/layers/wms/types/#DimensionInterval)s.
   * For example, continuing from the previous example, a [TimeSlider](https://developers.arcgis.com/javascript/latest/references/core/widgets/TimeSlider/) is configured using the extent from a TimeDimension.
   *
   * ```js
   * const dates = timeDimension.extent; // This time dimension is expressed as an array of dates.
   * const start = dates[0]; // Get the first and earliest date
   * const end = dates[dates.length -1]; // Get last date
   * const timeSlider = new TimeSlider({
   *   container: "timeSliderDiv",
   *   view: view,
   *   mode: "instant",
   *   timeVisible: true,
   *   loop: true,
   *   fullTimeExtent: { // The TimeSlider UI will span all dates
   *     start,
   *     end
   *   },
   *   stops: {
   *     dates // The TimeSlider thumb will snap exactly to each valid date
   *   }
   * })
   *
   * @since 4.20
   */
  get dimensions(): WMSDimension[] | null | undefined;
  /**
   * The MIME type that will be requested by popups.
   *
   * The only valid values are "text/html" and "text/plain" or whichever is support by the service with "text/html"
   * being preferred. For a list of all supported MIME types please refer to [featureInfoFormats](https://developers.arcgis.com/javascript/latest/references/core/layers/WMSLayer/#featureInfoFormats).
   *
   * @example
   * // Display the MIME-type that will requested by popups.
   * const layer = new WMSLayer({
   *   url: "http://ows.terrestris.de/osm/service",
   * });
   * await layer.load();
   * console.log(layer.featureInfoFormat); // text/html
   */
  accessor featureInfoFormat: FeatureInfoFormat | null | undefined;
  /**
   * This property lists all available MIME-types that can be used with the WMS service's _GetFeatureInfo_ request.
   * The _GetFeatureInfo_ request is indirectly used by popups.
   *
   * To take advantage of unsupported MIME-types, such as _application/json_, please refer to
   * [fetchFeatureInfoFunction](https://developers.arcgis.com/javascript/latest/references/core/layers/WMSLayer/#fetchFeatureInfoFunction).
   *
   * @since 4.25
   * @example
   * // Display a list of MIME-types supported by the WMS service's _GetFeatureInfo_ request.
   * const layer = new WMSLayer({
   *   url: "https://maps.dwd.de/geoserver/dwd/wms"
   * });
   * await layer.load();
   * console.log(layer.featureInfoFormats);
   * // ["text/plain", "application/vnd.ogc.gml", "text/xml", "application/vnd.ogc.gml/3.1.1", "text/xml; subtype=gml/3.1.1", "text/html", "text/javascript", "application/json"]
   */
  get featureInfoFormats(): string[] | null | undefined;
  /**
   * The URL for the WMS GetFeatureInfo call.
   *
   * @example
   * // The following snippet demonstrates how to retrieve feature information from a WMSLayer
   * //   when the View is clicked. This snippet assumes that the service associated with the
   * //   layer supports a GetFeatureInfo MIME-type of "application/json".
   * view.on("click", async ({ x, y }) => {
   *   // Get a comma delimited list of visible layers.
   *   const layers = layer.sublayers
   *     .filter(({ visible, queryable, name }) => visible && queryable && name)
   *     .map(({ name }) => name)
   *     .join();
   *
   *   const { xmin, ymin, xmax, ymax, spatialReference: { latestWkid, wkid} } = view.extent;
   *   const bbox = `${xmin},${ymin},${xmax},${ymax}`;
   *   const crs = `EPSG:${latestWkid ?? wkid}`;
   *
   *   const { data } = await request(layer.featureInfoUrl, {
   *     query: {
   *       SERVICE: "WMS",
   *       LAYERS: layers,
   *       QUERY_LAYERS: layers,
   *       REQUEST: "GetFeatureInfo",
   *       INFO_FORMAT: "application/json",
   *       FEATURE_COUNT: 5,
   *       BBOX: bbox,
   *       CRS: crs,
   *       WIDTH: view.width,
   *       HEIGHT: view.height,
   *       I: Math.round(x),
   *       J: Math.round(y)
   *     }
   *   });
   *
   *   console.log("geoJson", data);
   * });
   */
  accessor featureInfoUrl: string | null | undefined;
  /**
   * Function to override the default popup behavior of `WMSLayer`.
   *
   * By default, popups will make a `GetFeatureInfo` request specifying the [featureInfoFormat](https://developers.arcgis.com/javascript/latest/references/core/layers/WMSLayer/#featureInfoFormat)
   * mime-type. The `featureInfoFormat` property only supports `text/plain` or `text/html`.
   *
   * Use `fetchFeatureInfoFunction` to take advantage of other mime-types supported by the service such as JSON or GeoJSON.
   * See [featureInfoFormats](https://developers.arcgis.com/javascript/latest/references/core/layers/WMSLayer/#featureInfoFormats)) for a list of supported mime-types.
   *
   * @since 4.25
   * @example
   * const url = "https://maps.dwd.de/geoserver/dwd/wms";
   * const sublayerName = "RADOLAN-RW"; // title: "angeeichtes Radarkomposit (RW)"
   *
   * const layer = new WMSLayer({
   *   url,
   *   fetchFeatureInfoFunction: async (query) => {
   *     // Explicitly request a GeoJSON response.
   *     query.info_format = "application/json";
   *
   *     // Request the first five features (if any).
   *     query.feature_count = 5;
   *
   *     // Perform the web request.
   *     const { data } = await esriRequest(layer.featureInfoUrl, { query });
   *
   *     // Convert each GeoJSON feature into an Esri graphic.
   *     return data.features.map(
   *       (feature) => new Graphic({
   *         attributes: feature.properties,
   *
   *         // Define a popup template to format field names and values in a table.
   *         popupTemplate: {
   *           title: "{id}",
   *           content: [{
   *             type: "fields",
   *             fieldInfos: [
   *               { fieldName: "GRAY_INDEX", label: "Gray Index" },
   *               { fieldName: "TIME", label: "Time" }
   *             ]
   *           }]
   *         }
   *       })
   *     );
   *   }
   * });
   */
  accessor fetchFeatureInfoFunction: FetchFeatureInfoFunction | null | undefined;
  /** All bounding boxes defined for the layer. */
  get fullExtents(): Extent[] | null | undefined;
  set fullExtents(value: ExtentProperties[] | null | undefined);
  /**
   * The map image format (MIME type) to request.
   * Defaults to `image/png` if the WMS service supports it.
   * If not, it defaults to the value of the first `<Format>` in `<GetMap>` in the GetCapabilities response.
   */
  accessor imageFormat: WMSLayerFormatType | null | undefined;
  /**
   * Indicates the maximum height of the image exported by the service.
   *
   * @default 2048
   */
  accessor imageMaxHeight: number;
  /**
   * Indicates the maximum width of the image exported by the service.
   *
   * @default 2048
   * @since 4.4
   */
  accessor imageMaxWidth: number;
  /**
   * Indicates whether the background of the image exported by the service is transparent.
   *
   * @default true
   */
  accessor imageTransparency: boolean;
  /**
   * Indicates whether the layer will be included in the legend.
   *
   * @default true
   */
  accessor legendEnabled: boolean;
  /** The spatial reference of the layer. */
  get spatialReference(): SpatialReference;
  set spatialReference(value: SpatialReferenceProperties);
  /** List of spatialReference well known ids derived from the CRS elements of the first layer in the GetCapabilities request. */
  accessor spatialReferences: number[] | null | undefined;
  /**
   * A subset of the layer's [WMSSublayer](https://developers.arcgis.com/javascript/latest/references/core/layers/support/WMSSublayer/)s that will be displayed.
   *
   * If you set the sublayers property at the time of the layer's initialization, this will override the sublayer information from the service.
   * For example, if you define a sublayer at layer initialization based on the name, as shown in the snippet below, other sublayer properties,
   * such as the `legendUrl`, `minScale`, and `maxScale`, will be set to the default values from the API, not the values defined in the service.
   *
   * ```js
   * const wmsLayer = new WMSLayer({
   *   url: "url-to-wms-service",
   *   sublayers: [{
   *     name: "sublayer-name"
   *   }]
   * });
   * ```
   *
   * Alternatively, in order to retain the service's definition for each sublayer, update the
   * `sublayers` property after loading the layer as demonstrated below.
   *
   * ```js
   * const wmsLayer = new WMSLayer({
   *   url: "url-to-wms-service"
   * });
   * await wmsLayer.load();
   * const sublayer = wmsLayer.findSublayerByName("sublayer-name");
   * if (sublayer) {
   *   wmsLayer.sublayers = [sublayer];
   * }
   * ```
   */
  get sublayers(): Collection<WMSSublayer>;
  set sublayers(value: ReadonlyArrayOrCollection<WMSSublayerProperties>);
  /**
   * The layer's time extent. When the layer's [useViewTime](https://developers.arcgis.com/javascript/latest/references/core/layers/WMSLayer/#useViewTime) is `false`, the layer
   * instructs the view to show data from the layer based on this time extent.
   * If the `useViewTime` is `true`, and both layer and view time extents are set, then features that fall within
   * the intersection of the view and layer time extents will be displayed.
   * For example, if the layer's time extent is set to display features between 1970 and 1975 and
   * the view has a time extent set to 1972-1980, the effective time on the feature layer will be 1972-1975.
   *
   * @since 4.17
   * @example
   * if (!layer.useViewTime) {
   *   if (layer.timeExtent) {
   *     console.log("Current timeExtent:", layer.timeExtent.start, " - ", layer.timeExtent.end}
   *   } else {
   *     console.log("The layer will display data within the view's timeExtent.");
   *     console.log("Current view.timeExtent:", view.timeExtent.start, " - ", view.timeExtent.end}
   *   }
   * }
   * @example
   * // set the timeExtent on the layer and useViewTime false
   * // In this case, the layer will honor its timeExtent and ignore
   * // the view's timeExtent
   * const layer = new WMSLayer({
   *   url: "https://geo.weather.gc.ca/geomet",
   *   timeExtent: {
   *     start: new Date(Date.UTC(2020, 8, 12)),
   *     end:  new Date(Date.UTC(2020, 8, 14)),
   *   },
   *   useViewTime: false
   * });
   * @example
   * // timeExtent is set on the layer and the view
   * // In this case, the layer will display features that fall
   * // within the intersection of view and layer time extents
   * // features within Jan 1, 1976 - Jan 1, 1981 will be displayed
   * const view = new MapView({
   *   timeExtent: {
   *     start: new Date(1976, 0, 1),
   *     end: new Date(2002, 0, 1)
   *   }
   * });
   * const layer = new WMSLayer({
   *   url: myUrl,
   *   timeExtent: {
   *     start: new Date(1974, 0, 1),
   *     end: new Date(1981, 0, 1)
   *   }
   * });
   * @example
   * if (!layer.useViewTime) {
   *   if (layer.timeExtent) {
   *     console.log("Current timeExtent:", layer.timeExtent.start, " - ", layer.timeExtent.end}
   *   } else {
   *     console.log("The layer will display data within the view's timeExtent.");
   *     console.log("Current view.timeExtent:", view.timeExtent.start, " - ", view.timeExtent.end}
   *   }
   * }
   * @example
   * // set the timeExtent on the layer and useViewTime false
   * // In this case, the layer will honor its timeExtent and ignore
   * // the view's timeExtent
   * const layer = new ImageryLayer({
   *   url: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/ScientificData/SeaTemperature/ImageServer",
   *   timeExtent: {
   *     start: new Date(2014, 4, 18),
   *     end: new Date(2014, 4, 19)
   *   },
   *   useViewTime: false
   * });
   * @example
   * // timeExtent is set on the layer and the view
   * // In this case, the layer will display features that fall
   * // within the intersection of view and layer time extents
   * // features within Jan 1, 1976 - Jan 1, 1981 will be displayed
   * const view = new MapView({
   *   timeExtent: {
   *     start: new Date(1976, 0, 1),
   *     end: new Date(2002, 0, 1)
   *   }
   * });
   * const layer = new FeatureLayer({
   *   url: myUrl,
   *   timeExtent: {
   *     start: new Date(1974, 0, 1),
   *     end: new Date(1981, 0, 1)
   *   }
   * });
   */
  get timeExtent(): TimeExtent | null | undefined;
  set timeExtent(value: TimeExtentProperties | null | undefined);
  /**
   * TimeInfo provides information such as date fields that store
   * [start](https://developers.arcgis.com/javascript/latest/references/core/layers/support/TimeInfo/#startField)
   * and [end](https://developers.arcgis.com/javascript/latest/references/core/layers/support/TimeInfo/#endField) time
   * for each feature and the [TimeInfo.fullTimeExtent](https://developers.arcgis.com/javascript/latest/references/core/layers/support/TimeInfo/#fullTimeExtent)
   * for the layer. The `timeInfo` property is automatically set at layer initialization if the layer has one or more time dimensions.
   * The [TimeInfo.fullTimeExtent](https://developers.arcgis.com/javascript/latest/references/core/layers/support/TimeInfo/#fullTimeExtent) for `timeInfo` is
   * automatically set to the union of all time dimension extents.
   * The timeInfo parameters cannot be changed after the layer is [loaded](https://developers.arcgis.com/javascript/latest/references/core/layers/WMSLayer/#load).
   *
   * @since 4.17
   * @example
   * // create geojson layer from usgs earthquakes geojson feed
   * const geojsonLayer = new GeoJSONLayer({
   *   url: "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_month.geojson",
   *   copyright: "USGS Earthquakes",
   *   fields: [
   *     { "name": "mag", "type": "double" },
   *     { "name": "place", "type": "string" },
   *     { "name": "time", "type": "date" }, // date field
   *     { "name": "depth", "type": "double" }
   *   ],
   *   // timeInfo can be used to do temporal queries
   *   // set the startField and endField.
   *   // timeExtent is automatically calculated from the
   *   // the start and end date fields
   *   // The date values must be in milliseconds number from the UNIX epoch specified in UTC.
   *   timeInfo: {
   *     startField: "time"
   *   }
   * });
   */
  get timeInfo(): TimeInfo | null | undefined;
  set timeInfo(value: TimeInfoProperties | null | undefined);
  /**
   * A temporary offset of the time data based on a certain [TimeInterval](https://developers.arcgis.com/javascript/latest/references/core/time/TimeInterval/). This allows
   * users to overlay features from two or more time-aware layers with different time extents.
   * For example, if a layer has data recorded for the year 1970, an offset value of 2 years would temporarily shift the data to
   * 1972. You can then overlay this data with data recorded in 1972.
   * A time offset can be used for display purposes only. The query and selection are not affected by the offset.
   *
   * @since 4.17
   * @example
   * // Offset a CSV Layer containing hurricanes from 2015 so that they appear in 2019 (+4 years).
   * let layer = new CSVLayer({
   *   url: `hurricanes-and-storms-2015.csv`,
   *   timeOffset: {
   *     value: 4,
   *     unit: "years"
   *   },
   *   timeInfo: {
   *     startField: "ISO_time"
   *   },
   *   renderer: {
   *     type: "simple",
   *     symbol: {
   *       type: "simple-marker",
   *       size: 6,
   *       color: "red",
   *       outline: {
   *         width: 0.5,
   *         color: "black"
   *       }
   *     }
   *   }
   * });
   * @example
   * // Offset a CSV Layer containing hurricanes from 2015 so that they appear in 2019 (+4 years).
   * let layer = new CSVLayer({
   *   url: `hurricanes-and-storms-2015.csv`,
   *   timeOffset: {
   *     value: 4,
   *     unit: "years"
   *   },
   *   timeInfo: {
   *     startField: "ISO_time"
   *   },
   *   renderer: {
   *     type: "simple",
   *     symbol: {
   *       type: "simple-marker",
   *       size: 6,
   *       color: "red",
   *       outline: {
   *         width: 0.5,
   *         color: "black"
   *       }
   *     }
   *   }
   * });
   */
  get timeOffset(): TimeInterval | null | undefined;
  set timeOffset(value: TimeIntervalProperties | null | undefined);
  /**
   * The title of the layer used to identify it in places such as the [Legend](https://developers.arcgis.com/javascript/latest/references/map-components/components/arcgis-legend/)
   * and [LayerList](https://developers.arcgis.com/javascript/latest/references/core/widgets/LayerList/).
   *
   * When the layer is loaded from a portal item, the title of the portal item will be used.
   * If a layer is loaded as part of a webmap or a webscene, then the title of the layer as stored in the webmap/webscene will be used.
   */
  accessor title: string | null | undefined;
  /** The layer type provides a convenient way to check the type of the layer without the need to import specific layer modules. */
  get type(): "wms";
  /** The URL of the WMS service. */
  accessor url: string;
  /**
   * Determines if the layer will update its temporal data based on the view's
   * [View.timeExtent](https://developers.arcgis.com/javascript/latest/references/core/views/View/#timeExtent). When `false`, the layer will display its temporal
   * data based on the layer's [timeExtent](https://developers.arcgis.com/javascript/latest/references/core/layers/WMSLayer/#timeExtent), regardless of changes to the view.
   * If both view and layer time extents are set while this property is `true`, then the features that fall within
   * the intersection of the view and layer time extents will be displayed.
   * For example, if a layer's time extent is set to display features between 1970 and 1975 and
   * the view has a time extent set to 1972-1980, the effective time on the feature layer will be 1972-1975.
   *
   * @default true
   * @since 4.17
   * @example
   * if (wmsLayer.useViewTime) {
   *   console.log("Displaying data between:", view.timeExtent.start, " - ", view.timeExtent.end);
   * }
   * @example
   * if (featureLayer.useViewTime) {
   *   console.log("Displaying data between:", view.timeExtent.start, " - ", view.timeExtent.end);
   * }
   */
  accessor useViewTime: boolean;
  /**
   * The version of the [WMS specification](https://www.ogc.org/standards/wms/) used.
   * For example, `1.3.0`, `1.1.1`, `1.1` or `1.0`.
   */
  accessor version: string;
  /**
   * Fetching the WMS image.
   *
   * @param extent - The extent of the view.
   * @param width - The width of the view in pixels.
   * @param height - The height of the view in pixels.
   * @param options - The parameter options is an object with the following properties.
   * @returns Resolves to an object with the image data.
   */
  fetchImage(extent: Extent, width: number, height: number, options?: WMSLayerFetchImageOptions): Promise<HTMLImageElement | HTMLCanvasElement>;
  /**
   * Returns a [WMSSublayer](https://developers.arcgis.com/javascript/latest/references/core/layers/support/WMSSublayer/) based on the given sublayer id.
   *
   * @param id - The [WMSSublayer.id](https://developers.arcgis.com/javascript/latest/references/core/layers/support/WMSSublayer/#id) of the WMS sublayer.
   * @returns Returns the requested WMSSublayer.
   */
  findSublayerById(id: number): WMSSublayer | null | undefined;
  /**
   * Returns a [WMSSublayer](https://developers.arcgis.com/javascript/latest/references/core/layers/support/WMSSublayer/) based on the given sublayer name.
   *
   * @param name - The [WMSSublayer.name](https://developers.arcgis.com/javascript/latest/references/core/layers/support/WMSSublayer/#name) of the WMS sublayer.
   * @returns Returns the requested WMSSublayer.
   * @since 4.17
   * @example
   * // Display the title and description for the WMS sublayer named "RADAR_1KM_RDBR".
   * const wmsLayer = new WMSLayer({
   *   url: "https://geo.weather.gc.ca/geomet"
   * });
   * wmsLayer.load().then(() => {
   *   const subLayer = layer.findSublayerByName("RADAR_1KM_RDBR");
   *   console.log(`${subLayer.title}`);       // "RADAR - Radar reflectivity (Rain) (1 km) [dBZ]"
   *   console.log(`${subLayer.description}`); // "Composite of American and Canadian weather radars updated every 10 minutes"
   * });
   */
  findSublayerByName(name: string): WMSSublayer | null | undefined;
}
declare const WMSLayerSuperclass: typeof Layer & typeof MultiOriginJSONSupportMixin & typeof PortalLayer & typeof OperationalLayer & typeof ScaleRangeLayer & typeof RefreshableLayer & typeof TemporalLayer & typeof BlendLayer

export interface WMSLayerFetchImageOptions extends AbortOptions {
  /** The rotation in degrees of the exported image. */
  rotation?: number | null;
  /** The ratio of the resolution in physical pixels of the image to the resolution it will be displayed at. */
  pixelRatio?: number | null;
  /** The [TimeExtent](https://developers.arcgis.com/javascript/latest/references/core/time/TimeExtent/) of the exported image. */
  timeExtent?: TimeExtent | null;
}