import { TConsoleBase, ProstoLogger, TProstoLoggerOptions } from '@prostojs/logger';
import { AsyncLocalStorage } from 'node:async_hooks';

declare function useEventId(): {
    getId: () => string;
};

declare function useEventLogger(topic?: string): TConsoleBase;

declare function useRouteParams<T extends object = Record<string, string | string[]>>(): {
    params: T;
    get: <K extends keyof T>(name: K) => T[K];
};

interface TEventLoggerData {
    eventId: string;
}
declare class EventLogger extends ProstoLogger<TEventLoggerData> {
    constructor(eventId: string, opts?: TEventOptions['eventLogger']);
}

interface TGenericEvent {
    type: string;
    logger?: EventLogger;
    id?: string;
}
interface TEmpty {
}

interface TEventOptions {
    eventLogger?: {
        topic?: string;
    } & TProstoLoggerOptions<TEventLoggerData>;
}
interface TGenericContextStore<CustomEventType = TEmpty> {
    event: CustomEventType & TGenericEvent;
    options: TEventOptions;
    parentCtx?: TGenericContextStore;
    routeParams?: Record<string, string | string[]>;
    _ended?: boolean;
}
/**
 * AsyncLocalStorage instance
 *
 * Use on your own risk only if you know what you're doing
 */
declare const asyncStorage: AsyncLocalStorage<TGenericContextStore>;
/**
 * Create Wooks Context
 */
declare function createAsyncEventContext<S = TEmpty, EventTypeToCreate = TEmpty>(data: S & TGenericContextStore<EventTypeToCreate>): <T>(cb: (...a: any[]) => T) => T;
/**
 * Use Wooks Context
 */
declare function useAsyncEventContext<S = TEmpty, EventType = TEmpty>(expectedTypes?: string | string[]): TCtxHelpers<S & TGenericContextStore<EventType>>;
interface TCtxHelpers<T> {
    getCtx: () => T;
    store: <K extends keyof Required<T>>(key: K) => {
        value: T[K];
        hook: <K2 extends keyof Required<T>[K]>(key2: K2) => {
            value: Required<T>[K][K2];
            isDefined: boolean;
        };
        init: <K2 extends keyof Required<T>[K]>(key2: K2, getter: () => Required<Required<T>[K]>[K2]) => Required<Required<T>[K]>[K2];
        set: <K2 extends keyof Required<T>[K]>(key2: K2, v: Required<T[K]>[K2]) => Required<T[K]>[K2];
        get: <K2 extends keyof Required<T>[K]>(key2: K2) => Required<T>[K][K2] | undefined;
        has: <K2 extends keyof Required<T>[K]>(key2: K2) => boolean;
        del: <K2 extends keyof Required<T>[K]>(key2: K2) => void;
        entries: () => Array<[string, unknown]>;
        clear: () => void;
    };
    getStore: <K extends keyof T>(key: K) => T[K];
    setStore: <K extends keyof T>(key: K, v: T[K]) => void;
    setParentCtx: (parentCtx: unknown) => void;
    hasParentCtx: () => boolean;
    getParentCtx: <T2 = T>() => TCtxHelpers<T2>;
}

/**
 * ContextInjector
 *
 * Provides a way to inject context
 * Usefull when working with opentelemetry spans
 */
declare class ContextInjector<N> {
    with<T>(name: N, attributes: Record<string, string | number | boolean>, cb: TContextInjectorCallback<T>): T;
    with<T>(name: N, cb: TContextInjectorCallback<T>): T;
    hook(method: string, name: 'Handler:not_found' | 'Handler:routed', route?: string): void;
}
type TContextInjectorCallback<T> = () => T;
declare function getContextInjector<N = TContextInjectorHooks>(): ContextInjector<N>;
declare function replaceContextInjector(newCi: ContextInjector<string>): void;
type TContextInjectorHooks = 'Event:start';

declare function attachHook<V = unknown, T extends object | Function = object, P extends PropertyKey = 'value'>(target: T, opts: {
    get: () => V | undefined;
    set?: (value: V) => void;
}, name?: P): T & THook<V, P>;
type THook<T = string, K extends PropertyKey = 'value'> = {
    [key in K]: T;
};

export { ContextInjector, EventLogger, type TContextInjectorHooks, type TCtxHelpers, type TEmpty, type TEventLoggerData, type TEventOptions, type TGenericContextStore, type TGenericEvent, type THook, asyncStorage, attachHook, createAsyncEventContext, getContextInjector, replaceContextInjector, useAsyncEventContext, useEventId, useEventLogger, useRouteParams };
