import { FactoryType } from "../utils/factory_type";
declare namespace interfaces {
    export type DynamicValue<T> = (context: interfaces.Context) => T | Promise<T>;
    export type ContainerResolution<T> = T | Promise<T> | (T | Promise<T>)[];
    type AsyncCallback<TCallback> = TCallback extends (...args: infer TArgs) => infer TResult ? (...args: TArgs) => Promise<TResult> : never;
    export type BindingScope = "Singleton" | "Transient" | "Request";
    export type BindingType = "ConstantValue" | "Constructor" | "DynamicValue" | "Factory" | "Function" | "Instance" | "Invalid" | "Provider";
    export type TargetType = "ConstructorArgument" | "ClassProperty" | "Variable";
    export interface BindingScopeEnum {
        Request: interfaces.BindingScope;
        Singleton: interfaces.BindingScope;
        Transient: interfaces.BindingScope;
    }
    export interface BindingTypeEnum {
        ConstantValue: interfaces.BindingType;
        Constructor: interfaces.BindingType;
        DynamicValue: interfaces.BindingType;
        Factory: interfaces.BindingType;
        Function: interfaces.BindingType;
        Instance: interfaces.BindingType;
        Invalid: interfaces.BindingType;
        Provider: interfaces.BindingType;
    }
    export interface TargetTypeEnum {
        ConstructorArgument: interfaces.TargetType;
        ClassProperty: interfaces.TargetType;
        Variable: interfaces.TargetType;
    }
    export type Newable<T> = new (...args: never[]) => T;
    export interface Abstract<T> {
        prototype: T;
    }
    export type ServiceIdentifier<T = unknown> = (string | symbol | Newable<T> | Abstract<T>);
    export interface Clonable<T> {
        clone(): T;
    }
    export type BindingActivation<T> = (context: interfaces.Context, injectable: T) => T | Promise<T>;
    export type BindingDeactivation<T> = (injectable: T) => void | Promise<void>;
    export interface Binding<TActivated> extends Clonable<Binding<TActivated>> {
        id: number;
        moduleId: ContainerModuleBase["id"];
        activated: boolean;
        serviceIdentifier: ServiceIdentifier<TActivated>;
        constraint: ConstraintFunction;
        dynamicValue: DynamicValue<TActivated> | null;
        scope: BindingScope;
        type: BindingType;
        implementationType: Newable<TActivated> | TActivated | null;
        factory: FactoryCreator<unknown> | null;
        provider: ProviderCreator<unknown> | null;
        onActivation: BindingActivation<TActivated> | null;
        onDeactivation: BindingDeactivation<TActivated> | null;
        cache: null | TActivated | Promise<TActivated>;
    }
    export type SimpleFactory<T, U extends unknown[] = unknown[]> = (...args: U) => T;
    export type MultiFactory<T, U extends unknown[] = unknown[], V extends unknown[] = unknown[]> = (...args: U) => SimpleFactory<T, V>;
    export type Factory<T, U extends unknown[] = unknown[], V extends unknown[] = unknown[]> = SimpleFactory<T, U> | MultiFactory<T, U, V>;
    export type FactoryCreator<T, U extends unknown[] = unknown[], V extends unknown[] = unknown[]> = (context: Context) => Factory<T, U, V>;
    export type AutoNamedFactory<T> = SimpleFactory<T, [string]>;
    export type AutoFactory<T> = SimpleFactory<T, []>;
    export type FactoryTypeFunction<T = unknown> = (context: interfaces.Context) => T | Promise<T>;
    export interface FactoryDetails {
        factoryType: FactoryType;
        factory: FactoryTypeFunction | null;
    }
    export type Provider<T> = (...args: any[]) => (((...args: any[]) => Promise<T>) | Promise<T>);
    export type ProviderCreator<T> = (context: Context) => Provider<T>;
    export interface NextArgs<T = unknown> {
        avoidConstraints: boolean;
        contextInterceptor: ((contexts: Context) => Context);
        isMultiInject: boolean;
        targetType: TargetType;
        serviceIdentifier: interfaces.ServiceIdentifier<T>;
        key?: string | number | symbol;
        value?: unknown;
    }
    export type Next = (args: NextArgs) => (any | any[]);
    export type Middleware = (next: Next) => Next;
    export type ContextInterceptor = (context: interfaces.Context) => interfaces.Context;
    export interface Context {
        id: number;
        container: Container;
        plan: Plan;
        currentRequest: Request;
        addPlan(plan: Plan): void;
        setCurrentRequest(request: Request): void;
    }
    export type MetadataOrMetadataArray = Metadata | Metadata[];
    export interface Metadata<TValue = unknown> {
        key: string | number | symbol;
        value: TValue;
    }
    export interface Plan {
        parentContext: Context;
        rootRequest: Request;
    }
    export interface QueryableString {
        startsWith(searchString: string): boolean;
        endsWith(searchString: string): boolean;
        contains(searchString: string): boolean;
        equals(compareString: string): boolean;
        value(): string;
    }
    export type ResolveRequestHandler = (request: interfaces.Request) => unknown;
    export type RequestScope = Map<unknown, unknown>;
    export interface Request {
        id: number;
        serviceIdentifier: ServiceIdentifier;
        parentContext: Context;
        parentRequest: Request | null;
        childRequests: Request[];
        target: Target;
        bindings: Binding<unknown>[];
        requestScope: RequestScope | null;
        addChildRequest(serviceIdentifier: ServiceIdentifier, bindings: (Binding<unknown> | Binding<unknown>[]), target: Target): Request;
    }
    export interface Target {
        id: number;
        serviceIdentifier: ServiceIdentifier;
        type: TargetType;
        name: QueryableString;
        identifier: string | symbol;
        metadata: Metadata[];
        getNamedTag(): interfaces.Metadata<string> | null;
        getCustomTags(): interfaces.Metadata[] | null;
        hasTag(key: string | number | symbol): boolean;
        isArray(): boolean;
        matchesArray(name: interfaces.ServiceIdentifier): boolean;
        isNamed(): boolean;
        isTagged(): boolean;
        isOptional(): boolean;
        matchesNamedTag(name: string): boolean;
        matchesTag(key: string | number | symbol): (value: unknown) => boolean;
    }
    export interface ContainerOptions {
        autoBindInjectable?: boolean;
        defaultScope?: BindingScope;
        skipBaseClassChecks?: boolean;
    }
    export interface Container {
        id: number;
        parent: Container | null;
        options: ContainerOptions;
        bind<T>(serviceIdentifier: ServiceIdentifier<T>): BindingToSyntax<T>;
        rebind<T>(serviceIdentifier: interfaces.ServiceIdentifier<T>): interfaces.BindingToSyntax<T>;
        rebindAsync<T>(serviceIdentifier: interfaces.ServiceIdentifier<T>): Promise<interfaces.BindingToSyntax<T>>;
        unbind(serviceIdentifier: ServiceIdentifier): void;
        unbindAsync(serviceIdentifier: interfaces.ServiceIdentifier): Promise<void>;
        unbindAll(): void;
        unbindAllAsync(): Promise<void>;
        isBound(serviceIdentifier: ServiceIdentifier): boolean;
        isCurrentBound<T>(serviceIdentifier: ServiceIdentifier<T>): boolean;
        isBoundNamed(serviceIdentifier: ServiceIdentifier, named: string | number | symbol): boolean;
        isBoundTagged(serviceIdentifier: ServiceIdentifier, key: string | number | symbol, value: unknown): boolean;
        get<T>(serviceIdentifier: ServiceIdentifier<T>): T;
        getNamed<T>(serviceIdentifier: ServiceIdentifier<T>, named: string | number | symbol): T;
        getTagged<T>(serviceIdentifier: ServiceIdentifier<T>, key: string | number | symbol, value: unknown): T;
        getAll<T>(serviceIdentifier: ServiceIdentifier<T>): T[];
        getAllTagged<T>(serviceIdentifier: ServiceIdentifier<T>, key: string | number | symbol, value: unknown): T[];
        getAllNamed<T>(serviceIdentifier: ServiceIdentifier<T>, named: string | number | symbol): T[];
        getAsync<T>(serviceIdentifier: ServiceIdentifier<T>): Promise<T>;
        getNamedAsync<T>(serviceIdentifier: ServiceIdentifier<T>, named: string | number | symbol): Promise<T>;
        getTaggedAsync<T>(serviceIdentifier: ServiceIdentifier<T>, key: string | number | symbol, value: unknown): Promise<T>;
        getAllAsync<T>(serviceIdentifier: ServiceIdentifier<T>): Promise<T[]>;
        getAllTaggedAsync<T>(serviceIdentifier: ServiceIdentifier<T>, key: string | number | symbol, value: unknown): Promise<T[]>;
        getAllNamedAsync<T>(serviceIdentifier: ServiceIdentifier<T>, named: string | number | symbol): Promise<T[]>;
        onActivation<T>(serviceIdentifier: ServiceIdentifier<T>, onActivation: BindingActivation<T>): void;
        onDeactivation<T>(serviceIdentifier: ServiceIdentifier<T>, onDeactivation: BindingDeactivation<T>): void;
        resolve<T>(constructorFunction: interfaces.Newable<T>): T;
        load(...modules: ContainerModule[]): void;
        loadAsync(...modules: AsyncContainerModule[]): Promise<void>;
        unload(...modules: ContainerModuleBase[]): void;
        unloadAsync(...modules: ContainerModuleBase[]): Promise<void>;
        applyCustomMetadataReader(metadataReader: MetadataReader): void;
        applyMiddleware(...middleware: Middleware[]): void;
        snapshot(): void;
        restore(): void;
        createChild(): Container;
    }
    export type Bind = <T>(serviceIdentifier: ServiceIdentifier<T>) => BindingToSyntax<T>;
    export type Rebind = <T>(serviceIdentifier: ServiceIdentifier<T>) => BindingToSyntax<T>;
    export type Unbind = <T>(serviceIdentifier: ServiceIdentifier<T>) => void;
    export type UnbindAsync = <T>(serviceIdentifier: ServiceIdentifier<T>) => Promise<void>;
    export type IsBound = <T>(serviceIdentifier: ServiceIdentifier<T>) => boolean;
    export interface ContainerModuleBase {
        id: number;
    }
    export interface ContainerModule extends ContainerModuleBase {
        registry: ContainerModuleCallBack;
    }
    export interface AsyncContainerModule extends ContainerModuleBase {
        registry: AsyncContainerModuleCallBack;
    }
    export interface ModuleActivationHandlers {
        onActivations: Lookup<BindingActivation<unknown>>;
        onDeactivations: Lookup<BindingDeactivation<unknown>>;
    }
    export interface ModuleActivationStore extends Clonable<ModuleActivationStore> {
        addDeactivation(moduleId: ContainerModuleBase["id"], serviceIdentifier: ServiceIdentifier<unknown>, onDeactivation: interfaces.BindingDeactivation<unknown>): void;
        addActivation(moduleId: ContainerModuleBase["id"], serviceIdentifier: ServiceIdentifier<unknown>, onActivation: interfaces.BindingActivation<unknown>): void;
        remove(moduleId: ContainerModuleBase["id"]): ModuleActivationHandlers;
    }
    export type ContainerModuleCallBack = (bind: interfaces.Bind, unbind: interfaces.Unbind, isBound: interfaces.IsBound, rebind: interfaces.Rebind, unbindAsync: interfaces.UnbindAsync, onActivation: interfaces.Container["onActivation"], onDeactivation: interfaces.Container["onDeactivation"]) => void;
    export type AsyncContainerModuleCallBack = AsyncCallback<ContainerModuleCallBack>;
    export interface ContainerSnapshot {
        bindings: Lookup<Binding<unknown>>;
        activations: Lookup<BindingActivation<unknown>>;
        deactivations: Lookup<BindingDeactivation<unknown>>;
        middleware: Next | null;
        moduleActivationStore: interfaces.ModuleActivationStore;
    }
    export interface Lookup<T> extends Clonable<Lookup<T>> {
        add(serviceIdentifier: ServiceIdentifier, value: T): void;
        getMap(): Map<interfaces.ServiceIdentifier, T[]>;
        get(serviceIdentifier: ServiceIdentifier): T[];
        remove(serviceIdentifier: interfaces.ServiceIdentifier): void;
        removeByCondition(condition: (item: T) => boolean): T[];
        removeIntersection(lookup: interfaces.Lookup<T>): void;
        hasKey(serviceIdentifier: ServiceIdentifier): boolean;
        clone(): Lookup<T>;
        traverse(func: (key: interfaces.ServiceIdentifier, value: T[]) => void): void;
    }
    export interface BindingOnSyntax<T> {
        onActivation(fn: (context: Context, injectable: T) => T | Promise<T>): BindingWhenSyntax<T>;
        onDeactivation(fn: (injectable: T) => void | Promise<void>): BindingWhenSyntax<T>;
    }
    export interface BindingWhenSyntax<T> {
        when(constraint: (request: Request) => boolean): BindingOnSyntax<T>;
        whenTargetNamed(name: string | number | symbol): BindingOnSyntax<T>;
        whenTargetIsDefault(): BindingOnSyntax<T>;
        whenTargetTagged(tag: string | number | symbol, value: unknown): BindingOnSyntax<T>;
        whenInjectedInto(parent: (NewableFunction | string)): BindingOnSyntax<T>;
        whenParentNamed(name: string | number | symbol): BindingOnSyntax<T>;
        whenParentTagged(tag: string | number | symbol, value: unknown): BindingOnSyntax<T>;
        whenAnyAncestorIs(ancestor: (NewableFunction | string)): BindingOnSyntax<T>;
        whenNoAncestorIs(ancestor: (NewableFunction | string)): BindingOnSyntax<T>;
        whenAnyAncestorNamed(name: string | number | symbol): BindingOnSyntax<T>;
        whenAnyAncestorTagged(tag: string | number | symbol, value: unknown): BindingOnSyntax<T>;
        whenNoAncestorNamed(name: string | number | symbol): BindingOnSyntax<T>;
        whenNoAncestorTagged(tag: string | number | symbol, value: unknown): BindingOnSyntax<T>;
        whenAnyAncestorMatches(constraint: (request: Request) => boolean): BindingOnSyntax<T>;
        whenNoAncestorMatches(constraint: (request: Request) => boolean): BindingOnSyntax<T>;
    }
    export interface BindingWhenOnSyntax<T> extends BindingWhenSyntax<T>, BindingOnSyntax<T> {
    }
    export interface BindingInSyntax<T> {
        inSingletonScope(): BindingWhenOnSyntax<T>;
        inTransientScope(): BindingWhenOnSyntax<T>;
        inRequestScope(): BindingWhenOnSyntax<T>;
    }
    export interface BindingInWhenOnSyntax<T> extends BindingInSyntax<T>, BindingWhenOnSyntax<T> {
    }
    export interface BindingToSyntax<T> {
        to(constructor: new (...args: never[]) => T): BindingInWhenOnSyntax<T>;
        toSelf(): BindingInWhenOnSyntax<T>;
        toConstantValue(value: T): BindingWhenOnSyntax<T>;
        toDynamicValue(func: DynamicValue<T>): BindingInWhenOnSyntax<T>;
        toConstructor<T2>(constructor: Newable<T2>): BindingWhenOnSyntax<T>;
        toFactory<T2, T3 extends unknown[] = unknown[], T4 extends unknown[] = unknown[]>(factory: FactoryCreator<T2, T3, T4>): BindingWhenOnSyntax<T>;
        toFunction(func: T): BindingWhenOnSyntax<T>;
        toAutoFactory<T2>(serviceIdentifier: ServiceIdentifier<T2>): BindingWhenOnSyntax<T>;
        toAutoNamedFactory<T2>(serviceIdentifier: ServiceIdentifier<T2>): BindingWhenOnSyntax<T>;
        toProvider<T2>(provider: ProviderCreator<T2>): BindingWhenOnSyntax<T>;
        toService(service: ServiceIdentifier<T>): void;
    }
    export interface ConstraintFunction {
        metaData?: Metadata;
        (request: Request | null): boolean;
    }
    export interface MetadataReader {
        getConstructorMetadata(constructorFunc: NewableFunction): ConstructorMetadata;
        getPropertiesMetadata(constructorFunc: NewableFunction): MetadataMap;
    }
    export interface MetadataMap {
        [propertyNameOrArgumentIndex: string | symbol]: Metadata[];
    }
    export interface ConstructorMetadata {
        compilerGeneratedMetadata: NewableFunction[] | undefined;
        userGeneratedMetadata: MetadataMap;
    }
    export {};
}
export { interfaces };
