import * as i0 from '@angular/core';
import { ApplicationRef, InjectionToken, ModuleWithProviders, EnvironmentProviders } from '@angular/core';
import { ManagerOptions, Socket } from 'socket.io-client';
import { Observable } from 'rxjs';
import { EventsMap, DefaultEventsMap, ReservedOrUserEventNames, ReservedOrUserListener, EventParams, EventNames } from '@socket.io/component-emitter';
export { DefaultEventsMap, EventNames, EventParams, EventsMap, ReservedOrUserEventNames, ReservedOrUserListener } from '@socket.io/component-emitter';

/** Config interface */
interface SocketIoConfig {
    url: string;
    /**
     * Options
     * References:
     * https://socket.io/docs/v4/client-options
     */
    options?: Partial<ManagerOptions>;
}

type IoSocket<ListenEvents extends EventsMap = DefaultEventsMap, EmitEvents extends EventsMap = ListenEvents> = Socket<ListenEvents, EmitEvents>;
type First<T extends any[]> = T extends [infer F, ...infer L] ? F : any;
type Last<T extends any[]> = T extends [...infer H, infer L] ? L : any;
type AllButLast<T extends any[]> = T extends [...infer H, infer L] ? H : any[];
type FirstArg<T> = T extends (arg: infer Param) => infer Result ? Param : any;
type DisconnectDescription = Error | {
    description: string;
    context?: unknown;
};
interface SocketReservedEvents {
    connect: () => void;
    connect_error: (err: Error) => void;
    disconnect: (reason: Socket.DisconnectReason, description?: DisconnectDescription) => void;
}
type IgnoredWrapperEvents = 'receiveBuffer' | 'sendBuffer';
type WrappedSocketIface<Wrapper> = {
    [K in Exclude<keyof IoSocket, IgnoredWrapperEvents>]: IoSocket[K] extends (...args: any[]) => IoSocket ? (...args: Parameters<IoSocket[K]>) => Wrapper : IoSocket[K] extends IoSocket ? Wrapper : IoSocket[K];
};
declare class WrappedSocket<ListenEvents extends EventsMap = DefaultEventsMap, EmitEvents extends EventsMap = ListenEvents> implements WrappedSocketIface<WrappedSocket> {
    private config;
    private appRef;
    private readonly subscribersCounter;
    private readonly eventObservables$;
    private readonly namespaces;
    readonly ioSocket: IoSocket<ListenEvents, EmitEvents>;
    private readonly emptyConfig;
    constructor(config: SocketIoConfig, appRef: ApplicationRef);
    get auth(): Socket['auth'];
    set auth(value: Socket['auth']);
    /** readonly access to io manager */
    get io(): Socket['io'];
    /** alias to connect */
    get open(): WrappedSocket['connect'];
    /** alias to disconnect */
    get close(): WrappedSocket['disconnect'];
    /**
     * Gets a WrappedSocket for the given namespace.
     *
     * @note if an existing socket exists for the given namespace, it will be reused.
     *
     * @param namespace the namespace to create a new socket based on the current config.
     *        If empty or `/`, then the current instance is returned.
     * @returns a socket that is bound to the given namespace. If namespace is empty or `/`,
     *          then `this` is returned, otherwise another instance is returned, creating
     *          it if it's the first use of such namespace.
     */
    of(namespace: string): WrappedSocket;
    on<Ev extends ReservedOrUserEventNames<SocketReservedEvents, ListenEvents>>(eventName: Ev, callback: ReservedOrUserListener<SocketReservedEvents, ListenEvents, Ev>): this;
    once<Ev extends ReservedOrUserEventNames<SocketReservedEvents, ListenEvents>>(eventName: Ev, callback: ReservedOrUserListener<SocketReservedEvents, ListenEvents, Ev>): this;
    connect(): this;
    disconnect(): this;
    emit<Ep extends EventParams<EmitEvents, Ev>, Ev extends EventNames<EmitEvents> = EventNames<EmitEvents>>(eventName: Ev, ...args: Ep): this;
    send(..._args: any[]): this;
    emitWithAck<Ep extends EventParams<EmitEvents, Ev>, Ev extends EventNames<EmitEvents> = EventNames<EmitEvents>>(eventName: Ev, ...args: AllButLast<Ep>): Promise<FirstArg<Last<Ep>>>;
    removeListener<Ev extends ReservedOrUserEventNames<SocketReservedEvents, ListenEvents>>(eventName?: Ev, callback?: ReservedOrUserListener<SocketReservedEvents, ListenEvents, Ev>): this;
    removeAllListeners<Ev extends ReservedOrUserEventNames<SocketReservedEvents, ListenEvents>>(eventName?: Ev): this;
    fromEvent<Ep extends First<EventParams<ListenEvents, Ev>>, Ev extends ReservedOrUserEventNames<SocketReservedEvents, ListenEvents> = ReservedOrUserEventNames<SocketReservedEvents, ListenEvents>>(eventName: Ev): Observable<Ep>;
    fromOneTimeEvent<Ep extends ReservedOrUserListener<SocketReservedEvents, ListenEvents, Ev>, Ev extends ReservedOrUserEventNames<SocketReservedEvents, ListenEvents> = ReservedOrUserEventNames<SocketReservedEvents, ListenEvents>>(eventName: Ev): Promise<Ep>;
    listeners<Ev extends ReservedOrUserEventNames<SocketReservedEvents, ListenEvents>>(eventName: Ev): ReservedOrUserListener<SocketReservedEvents, ListenEvents, Ev>[];
    hasListeners<Ev extends ReservedOrUserEventNames<SocketReservedEvents, ListenEvents>>(eventName: Ev): boolean;
    listenersAny(): ((...args: any[]) => void)[];
    listenersAnyOutgoing(): ((...args: any[]) => void)[];
    off<Ev extends ReservedOrUserEventNames<SocketReservedEvents, ListenEvents>>(eventName?: Ev, listener?: ReservedOrUserListener<SocketReservedEvents, ListenEvents, Ev>): this;
    offAny(callback?: (event: string, ...args: any[]) => void): this;
    offAnyOutgoing(callback?: (event: string, ...args: any[]) => void): this;
    onAny(callback: (event: string, ...args: any[]) => void): this;
    onAnyOutgoing(callback: (event: string, ...args: any[]) => void): this;
    prependAny(callback: (event: string, ...args: any[]) => void): this;
    prependAnyOutgoing(callback: (event: string | symbol, ...args: any[]) => void): this;
    timeout(value: number): this;
    get volatile(): this;
    get active(): Socket['active'];
    get connected(): Socket['connected'];
    get disconnected(): Socket['disconnected'];
    get recovered(): Socket['recovered'];
    get id(): Socket['id'];
    compress(value: boolean): this;
}

declare const SOCKET_CONFIG_TOKEN: InjectionToken<SocketIoConfig>;
declare class SocketIoModule {
    static forRoot(config: SocketIoConfig): ModuleWithProviders<SocketIoModule>;
    static ɵfac: i0.ɵɵFactoryDeclaration<SocketIoModule, never>;
    static ɵmod: i0.ɵɵNgModuleDeclaration<SocketIoModule, never, never, never>;
    static ɵinj: i0.ɵɵInjectorDeclaration<SocketIoModule>;
}
declare const provideSocketIo: (config: SocketIoConfig) => EnvironmentProviders;

export { SOCKET_CONFIG_TOKEN, WrappedSocket as Socket, SocketIoModule, provideSocketIo };
export type { AllButLast, First, FirstArg, Last, SocketIoConfig };
