import type Accessor from "./Accessor.js";
import type { ResourceHandle } from "./Handles.js";

/** @since 4.0 */
export abstract class EventedMixin {
  constructor(...args: any[]);
  /**
   * @deprecated
   * Do not directly reference this property.
   * Use EventNames and EventTypes helpers from \@arcgis/core/Evented
   */
  readonly "@eventTypes": unknown;
  /**
   * Emits an event on the instance. This method should only be used when creating subclasses of this class.
   *
   * @param type - The name of the event.
   * @param event - The event payload.
   * @returns `true` if a listener was notified
   * @since 4.5
   */
  emit<Type extends EventNames<this>>(type: Type, event?: this["@eventTypes"][Type]): boolean;
  /**
   * Indicates whether there is an event listener on the instance that matches
   * the provided event name.
   *
   * @param type - The name of the event.
   * @returns Returns true if the class supports the input event.
   */
  hasEventListener<Type extends EventNames<this>>(type: Type): boolean;
  /**
   * Registers an event handler on the instance. Call this method to hook an event with a listener.
   *
   * @param type - An [event](#events-summary) or an array of events to listen for.
   * @param listener - The function to call when the event fires.
   * @returns Returns an event handler with a `remove()` method that should be called to stop listening for the event(s).
   *
   * Property | Type | Description
   * ------------|--------|----------------
   * remove | Function | When called, removes the listener from the event.
   * @example
   * view.on("click", function(event){
   *   // event is the event handle returned after the event fires.
   *   console.log(event.mapPoint);
   * });
   */
  on<Type extends EventNames<this>>(type: Type, listener: EventedCallback<this["@eventTypes"][Type]>): ResourceHandle;
}

/** Evented is a base class for objects that can emit events. It is used by many classes in the ArcGIS API for JavaScript to provide event handling capabilities. */
export abstract class Evented extends EventedMixin {}

export abstract class EventedAccessor extends EventedAccessorSuperclass {}
declare const EventedAccessorSuperclass: & typeof Accessor & typeof EventedMixin

export type EventedCallback<T = any> = ((event: T) => void) | WeakRef<(event: T) => void>;

export type EventNames<Evented extends { "@eventTypes": unknown; }> = keyof Evented["@eventTypes"] &
  string;

export type EventTypes<T> = T extends EventedMixin ? T["@eventTypes"] : never;