import { Pin } from '@hazae41/box';
import { Future } from '@hazae41/future';
import { Option } from '@hazae41/option';
import { WeakParameters } from '../libs/parameters/index.js';
import { Awaitable } from '../libs/promises/index.js';
import { Voidable } from '../libs/voidable/index.js';

type SuperEventDescriptor = (...args: any) => any;
type SuperEventMap = Record<string, SuperEventDescriptor>;
type SuperEventListener<T extends SuperEventDescriptor> = (...params: WeakParameters<T>) => Awaitable<Voidable<Option<ReturnType<T>>>>;
type SuperEventWaiter<T extends SuperEventDescriptor, R> = (future: Future<R>, ...params: WeakParameters<T>) => Awaitable<Voidable<Option<ReturnType<T>>>>;
declare class SuperEventTarget<M extends SuperEventMap> {
    #private;
    get listeners(): Map<keyof M, Map<SuperEventListener<any>, AddEventListenerOptions & Disposable>>;
    /**
     * Add a listener to an event
     * @param type Event type //  "abort", "error", "message", "close"
     * @param listener Event listener // (e) => new Some(123)
     * @param options Options // { passive: true }
     * @returns
     */
    on<K extends keyof M>(type: K, listener: SuperEventListener<M[K]>, options?: AddEventListenerOptions): () => void;
    /**
     * Remove a listener from an event
     * @param type Event type //  "abort", "error", "message", "close"
     * @param listener Event listener // (e) => console.log("hello")
     * @param options Just to look like DOM's EventTarget
     * @returns
     */
    off<K extends keyof M>(type: K, listener: SuperEventListener<M[K]>): void;
    /**
     * Dispatch an event to its listeners
     *
     * - Dispatch to active listeners sequencially
     * - Return if one of the listeners returned something
     * - Dispatch to passive listeners concurrently
     * - Return if one of the listeners returned something
     * - Return nothing
     * @param params The object to emit
     * @returns `Some` if the event
     */
    emit<K extends keyof M>(type: K, ...params: WeakParameters<M[K]>): Promise<Option<ReturnType<M[K]>>>;
    /**
     * Like `.on`, but instead of returning to the target, capture the returned value in a future, and return nothing to the target
     * @param type
     * @param callback
     * @returns
     */
    wait<K extends keyof M, R>(type: K, callback: SuperEventWaiter<M[K], R>): Pin<Promise<R>>;
}

export { SuperEventTarget };
export type { SuperEventDescriptor, SuperEventListener, SuperEventMap, SuperEventWaiter };
