import type EsriError from "../../core/Error.js";
import type FeatureSet from "../../rest/support/FeatureSet.js";
import type Query from "../../rest/support/Query.js";
import type FeatureLikeLayerView from "./FeatureLikeLayerView.js";
import type { AbortOptions } from "../../core/promiseUtils.js";
import type { Message } from "../../layers/support/StreamConnection.js";
import type { Feature } from "../../portal/jsonTypes.js";

/**
 * The [update-event](https://developers.arcgis.com/javascript/latest/references/core/views/layers/StreamLayerView/#event-update-rate)'s payload.
 * The update rate of features being processed on the client and pushed from the server.
 *
 * @see [@update-rate](https://developers.arcgis.com/javascript/latest/references/core/views/layers/StreamLayerView/#event-update-rate)
 */
export interface StreamUpdateRateEvent {
  /** The client update rate per second. Returns number of features being processed on the client. */
  client: number;
  /** Update rate per second for websocket/service. Returns number of features being pushed from the server. */
  websocket: number;
}

export interface StreamLayerViewEvents {
  /**
   * Fires when the layer view receives a message sent to the websocket connection.
   *
   * @since 4.26
   */
  "message-received": Message;
  /**
   * Fires when the layer view receives features. The event payload contains
   * the attributes and geometry of a feature received from the stream service.
   */
  "data-received": Pick<Feature, "attributes" | "geometry">;
  /**
   * Fires after the layer starts receiving updates from the stream service. It will return the websocket and the client update rates per second.
   * The update rate indicates number of features are being pushed from the server and being processed on the client side.
   * The client update rate will be approximately equal to the websocket update rate unless the service is pushing updates at a rate faster
   * than the client can handle. In which case, the API will down-throttle the update rate and will cause the client update rate to be lower.
   *
   * @since 4.17
   */
  "update-rate": StreamUpdateRateEvent;
}

/**
 * Represents the [LayerView](https://developers.arcgis.com/javascript/latest/references/core/views/layers/LayerView/) of a [StreamLayer](https://developers.arcgis.com/javascript/latest/references/core/layers/StreamLayer/)
 * after it has been added to a [Map](https://developers.arcgis.com/javascript/latest/references/core/Map/) in either a [MapView](https://developers.arcgis.com/javascript/latest/references/core/views/MapView/), [Map component](https://developers.arcgis.com/javascript/latest/references/map-components/components/arcgis-map/),
 * [SceneView](https://developers.arcgis.com/javascript/latest/references/core/views/SceneView/) or [Scene component](https://developers.arcgis.com/javascript/latest/references/map-components/components/arcgis-scene/).
 *
 * The StreamLayerView is responsible for rendering a [StreamLayer's](https://developers.arcgis.com/javascript/latest/references/core/layers/StreamLayer/)
 * features as [graphics](https://developers.arcgis.com/javascript/latest/references/core/Graphic/) in the [View](https://developers.arcgis.com/javascript/latest/references/core/views/View/). The [methods](https://developers.arcgis.com/javascript/latest/references/core/views/layers/StreamLayerView/#queryExtent)
 * in the StreamLayerView provide developers with the ability to query and highlight graphics in the view. See the
 * code snippets in the [methods](https://developers.arcgis.com/javascript/latest/references/core/views/layers/StreamLayerView/#queryExtent) below for examples of how to access client-side graphics from the
 * view.
 *
 * It connects to a server that emits geographic features continuously. The stream layer is suitable when you would like
 * to map dynamic streams of data that are unbounded and
 * continuous. When a StreamLayer is added to a map, users are able to see any real-time updates
 * pushed out by the server. For more information, read the documentation of
 * [StreamLayer](https://developers.arcgis.com/javascript/latest/references/core/layers/StreamLayer/).
 *
 * @since 4.4
 * @see [StreamLayer](https://developers.arcgis.com/javascript/latest/references/core/layers/StreamLayer/)
 * @see [Sample - Add StreamLayer to your Map](https://developers.arcgis.com/javascript/latest/sample-code/layers-streamlayer/)
 */
export default abstract class StreamLayerView extends FeatureLikeLayerView {
  /**
   * @deprecated
   * Do not directly reference this property.
   * Use EventNames and EventTypes helpers from \@arcgis/core/Evented
   */
  "@eventTypes": StreamLayerViewEvents;
  /**
   * The error that explains an unsuccessful attempt to connect to the
   * stream service or an unexpected disconnection from the stream service.
   */
  get connectionError(): EsriError | null;
  /**
   * The status of the Web Socket connection with the stream service. This property
   * can be watched to see if the connection is lost unexpectedly.
   *
   * Release specific changes:
   * * At version 4.29, [connect()](https://developers.arcgis.com/javascript/latest/references/core/views/layers/StreamLayerView/#connect) and [disconnect()](https://developers.arcgis.com/javascript/latest/references/core/views/layers/StreamLayerView/#disconnect) methods were added.  Consequently, invoking the `disconnect()`
   * method following a `pause` will transition the connection status from `paused` to `disconnected`. Subsequent use of the `connect()` method
   * will then change the connection status to `connected`.
   * * At version 4.26, the `connectionStatus` can be `paused` if the [pause()](https://developers.arcgis.com/javascript/latest/references/core/views/layers/StreamLayerView/#pause) method is called or
   * if the layer becomes [suspended](https://developers.arcgis.com/javascript/latest/references/core/views/layers/LayerView/#suspended).
   */
  get connectionStatus(): StreamLayerViewConnectionStatus;
  /**
   * Connects to a stream service web socket. The web socket will start streaming new observations.
   * It changes the [connectionStatus](https://developers.arcgis.com/javascript/latest/references/core/views/layers/StreamLayerView/#connectionStatus) to `connected`.
   *
   * @since 4.29
   * @see [disconnect()](https://developers.arcgis.com/javascript/latest/references/core/views/layers/StreamLayerView/#disconnect)
   */
  connect(): void;
  /**
   * Disconnects from a stream service web socket. New observations will not be streamed until [connect()](https://developers.arcgis.com/javascript/latest/references/core/views/layers/StreamLayerView/#connect) method is called.
   * It changes the [connectionStatus](https://developers.arcgis.com/javascript/latest/references/core/views/layers/StreamLayerView/#connectionStatus) to `disconnected`.
   *
   * @since 4.29
   * @see [connect()](https://developers.arcgis.com/javascript/latest/references/core/views/layers/StreamLayerView/#connect)
   */
  disconnect(): void;
  /**
   * Pauses the connection and stops new observations from being applied until [resume()](https://developers.arcgis.com/javascript/latest/references/core/views/layers/StreamLayerView/#resume) is called.
   * The web socket is open and is still sending data but the layer view will not update.
   * It changes the [connectionStatus](https://developers.arcgis.com/javascript/latest/references/core/views/layers/StreamLayerView/#connectionStatus) to `paused`.
   *
   * At version 4.29, invoking the [disconnect()](https://developers.arcgis.com/javascript/latest/references/core/views/layers/StreamLayerView/#disconnect) method following a `pause` will transition the [connectionStatus](https://developers.arcgis.com/javascript/latest/references/core/views/layers/StreamLayerView/#connectionStatus) from `paused` to `disconnected`.
   * Subsequent use of the [connect()](https://developers.arcgis.com/javascript/latest/references/core/views/layers/StreamLayerView/#connect) method will then change the connectionStatus to `connected`.
   *
   * @since 4.26
   * @see [resume()](https://developers.arcgis.com/javascript/latest/references/core/views/layers/StreamLayerView/#resume)
   */
  pause(): void;
  /**
   * If a [TimeInfo.trackIdField](https://developers.arcgis.com/javascript/latest/references/core/layers/support/TimeInfo/#trackIdField) is specified on the stream service,
   * this method executes a [Query](https://developers.arcgis.com/javascript/latest/references/core/rest/support/Query/) against features available for drawing in the layerView and
   * returns a [FeatureSet](https://developers.arcgis.com/javascript/latest/references/core/rest/support/FeatureSet/) of the latest observations for each `trackId`
   * that satisfy the query. Otherwise, an [Error](https://developers.arcgis.com/javascript/latest/references/core/core/Error/) will be thrown when the method is called.
   *
   * > [!WARNING]
   * >
   * > **Known Limitations**
   * >
   * > Spatial queries have the same limitations as those listed in the [projectOperator](https://developers.arcgis.com/javascript/latest/references/core/geometry/operators/projectOperator/)
   * >   documentation.
   * > Spatial queries are not currently supported if the layerView has any of the following [SpatialReferences](https://developers.arcgis.com/javascript/latest/references/core/geometry/SpatialReference/):
   * >   - GDM 2000 (4742) – Malaysia
   * >   - Gusterberg (Ferro) (8042) – Austria/Czech Republic
   * >   - ISN2016 (8086) - Iceland
   * >   - SVY21 (4757) - Singapore
   *
   * @param query - Specifies the attributes, spatial, and temporal filter of the query.
   * When no parameters are passed to this method, all features in the client are returned. To only return features
   * visible in the view, set the `geometry` parameter in the query object to the view's extent.
   * @param options - An object with the following properties.
   * @returns When resolved, returns the [FeatureSet](https://developers.arcgis.com/javascript/latest/references/core/rest/support/FeatureSet/) that satisfy the input query.
   * @since 4.9
   * @example
   * let layer = new StreamLayer({
   *   url: streamLayerUrl  // URL to a Stream Service
   * });
   *
   * const layerView = await view.whenLayerView(layer);
   * await reactiveUtils.whenOnce(() => !layerView.updating);
   *
   * const results = await layerView.queryLatestObservations()
   * console.log(results.features);  // prints all the client-side graphics to the console
   */
  abstract queryLatestObservations(query?: Query, options?: AbortOptions): Promise<FeatureSet>;
  /**
   * Resumes the connection and the new observations will be applied. The layer view will update to show changes.
   * It changes the [connectionStatus](https://developers.arcgis.com/javascript/latest/references/core/views/layers/StreamLayerView/#connectionStatus) to `connected` if the connection is successful.
   * If the `connectionStatus` is set to `disconnected`, invoking this method will have no impact.
   *
   * @since 4.26
   * @see [pause()](https://developers.arcgis.com/javascript/latest/references/core/views/layers/StreamLayerView/#pause)
   */
  resume(): void;
}

/**
 * The status of the Web Socket connection with the stream service.
 *
 * @see [connectionStatus](https://developers.arcgis.com/javascript/latest/references/core/views/layers/StreamLayerView/#connectionStatus)
 */
export type StreamLayerViewConnectionStatus = "connected" | "disconnected" | "paused";