import type EsriError from "../../core/Error.js";
import type { EventedAccessor } from "../../core/Evented.js";
import type { StreamConnectionStatus } from "./types.js";
import type { Feature } from "../../portal/jsonTypes.js";
import type { ObjectId } from "../../views/types.js";

export interface StreamConnectionEvents {
  /** Fires when the stream connection receives data. The event object contains the message properties received from the stream service. */
  "data-received": Feature;
}

/**
 * A message to add [Features](https://developers.arcgis.com/javascript/latest/references/core/portal/jsonTypes/#Feature) to a [StreamLayer](https://developers.arcgis.com/javascript/latest/references/core/layers/StreamLayer/) on the client
 * by calling its [sendMessageToClient()](https://developers.arcgis.com/javascript/latest/references/core/layers/StreamLayer/#sendMessageToClient) method.
 * An array of JSON [Features](https://developers.arcgis.com/javascript/latest/references/core/portal/jsonTypes/#Feature) that can be added to a [StreamLayer](https://developers.arcgis.com/javascript/latest/references/core/layers/StreamLayer/) on the client by calling its
 * [sendMessageToClient()](https://developers.arcgis.com/javascript/latest/references/core/layers/StreamLayer/#sendMessageToClient) method.
 * Each feature is an esri Feature JSON object as defined in the
 * [Feature object specification](https://next.gha.arcgis.com/documentation/common-data-types/feature-object.htm).
 */
export interface FeatureMessage {
  /** The type of message being sent to the client. */
  type: "features";
  /** An array of JSON [Features](https://developers.arcgis.com/javascript/latest/references/core/portal/jsonTypes/#Feature) to add to a [StreamLayer](https://developers.arcgis.com/javascript/latest/references/core/layers/StreamLayer/) on the client. */
  features: Feature[];
}

/**
 * A message to delete features from a [StreamLayer](https://developers.arcgis.com/javascript/latest/references/core/layers/StreamLayer/) on the client by calling its
 * [sendMessageToClient()](https://developers.arcgis.com/javascript/latest/references/core/layers/StreamLayer/#sendMessageToClient) method.
 */
export interface DeleteMessage {
  /** The type of message being sent to the client. */
  type: "delete";
  /** An array of track IDs identifying the features to delete from a [StreamLayer](https://developers.arcgis.com/javascript/latest/references/core/layers/StreamLayer/) on the client. */
  trackIds: number[];
  /** An array of object IDs identifying the features to delete from a [StreamLayer](https://developers.arcgis.com/javascript/latest/references/core/layers/StreamLayer/) on the client. */
  objectIds: ObjectId[];
}

/**
 * A message to clear all features from a [StreamLayer](https://developers.arcgis.com/javascript/latest/references/core/layers/StreamLayer/) on the client by calling its
 * [sendMessageToClient()](https://developers.arcgis.com/javascript/latest/references/core/layers/StreamLayer/#sendMessageToClient) method.
 */
export interface ClearMessage {
  /** The type of message being sent to the client. */
  type: "clear";
}

/** The message to send to a [StreamLayer](https://developers.arcgis.com/javascript/latest/references/core/layers/StreamLayer/) on the client by calling its [sendMessageToClient()](https://developers.arcgis.com/javascript/latest/references/core/layers/StreamLayer/#sendMessageToClient) method. */
export type Message = FeatureMessage | DeleteMessage | ClearMessage | object;

/**
 * A web socket connection to a stream service. The connection to the stream service can be established
 * by calling [StreamLayer's connect()](https://developers.arcgis.com/javascript/latest/references/core/layers/StreamLayer/#connect) method.
 *
 * @since 4.25
 * @see [StreamLayer.connect()](https://developers.arcgis.com/javascript/latest/references/core/layers/StreamLayer/#connect)
 * @example
 * // get layer's connection configurations
 * const parameters = layer.createConnectionParameters();
 *
 * // set the spatial reference of the service geometries
 * parameters.spatialReference = new SpatialReference({
 *   wkid: 2154
 * });
 *
 * const connection = await layer.connect(parameters);
 *
 * // listen to date-received event once the connection is established
 * // create a graphic from the JSON object returned and add them to view
 * connection.on("data-received", (feature) => {
 *   const graphic = Graphic.fromJSON(feature);
 *   graphic.symbol = myPointSymbol;
 *   view.graphics.push(graphic);
 * });
 *
 * // close the connection when it is not needed anymore
 * connection.destroy();
 */
export default abstract class StreamConnection extends EventedAccessor {
  /**
   * @deprecated
   * Do not directly reference this property.
   * Use EventNames and EventTypes helpers from \@arcgis/core/Evented
   */
  "@eventTypes": StreamConnectionEvents;
  /**
   * 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 | undefined;
  /**
   * The status of the Web Socket connection with the stream service. This property
   * can be watched to see if the connection is lost unexpectedly.
   */
  abstract readonly connectionStatus: StreamConnectionStatus;
  /** Destroys the existing connection instance to the stream service. */
  destroy(): void;
}