import { BaseHook, HookHints, EvaluationDetails, JsonValue, FlagValue, CommonProvider, ClientProviderStatus, EvaluationContext, Logger, ResolutionDetails, ClientProviderEvents, GenericEventEmitter, TrackingEventDetails, EvaluationLifeCycle, ManageLogger, Eventing, ClientMetadata, OpenFeatureCommonAPI, ManageContext, ProviderWrapper } from '@openfeature/core';
export * from '@openfeature/core';
export { ClientProviderEvents as ProviderEvents, ClientProviderStatus as ProviderStatus } from '@openfeature/core';

interface FlagEvaluationOptions {
    hooks?: BaseHook[];
    hookHints?: HookHints;
}
interface Features {
    /**
     * Performs a flag evaluation that returns a boolean.
     * @param {string} flagKey The flag key uniquely identifies a particular flag
     * @param {boolean} defaultValue The value returned if an error occurs
     * @param {FlagEvaluationOptions} options Additional flag evaluation options
     * @returns {boolean} Flag evaluation response
     */
    getBooleanValue(flagKey: string, defaultValue: boolean, options?: FlagEvaluationOptions): boolean;
    /**
     * Performs a flag evaluation that a returns an evaluation details object.
     * @param {string} flagKey The flag key uniquely identifies a particular flag
     * @param {boolean} defaultValue The value returned if an error occurs
     * @param {FlagEvaluationOptions} options Additional flag evaluation options
     * @returns {EvaluationDetails<boolean>} Flag evaluation details response
     */
    getBooleanDetails(flagKey: string, defaultValue: boolean, options?: FlagEvaluationOptions): EvaluationDetails<boolean>;
    /**
     * Performs a flag evaluation that returns a string.
     * @param {string} flagKey The flag key uniquely identifies a particular flag
     * @template {string} T A optional generic argument constraining the string
     * @param {T} defaultValue The value returned if an error occurs
     * @param {FlagEvaluationOptions} options Additional flag evaluation options
     * @returns {T} Flag evaluation response
     */
    getStringValue(flagKey: string, defaultValue: string, options?: FlagEvaluationOptions): string;
    getStringValue<T extends string = string>(flagKey: string, defaultValue: T, options?: FlagEvaluationOptions): T;
    /**
     * Performs a flag evaluation that a returns an evaluation details object.
     * @param {string} flagKey The flag key uniquely identifies a particular flag
     * @template {string} T A optional generic argument constraining the string
     * @param {T} defaultValue The value returned if an error occurs
     * @param {FlagEvaluationOptions} options Additional flag evaluation options
     * @returns {EvaluationDetails<T>} Flag evaluation details response
     */
    getStringDetails(flagKey: string, defaultValue: string, options?: FlagEvaluationOptions): EvaluationDetails<string>;
    getStringDetails<T extends string = string>(flagKey: string, defaultValue: T, options?: FlagEvaluationOptions): EvaluationDetails<T>;
    /**
     * Performs a flag evaluation that returns a number.
     * @param {string} flagKey The flag key uniquely identifies a particular flag
     * @template {number} T A optional generic argument constraining the number
     * @param {T} defaultValue The value returned if an error occurs
     * @param {FlagEvaluationOptions} options Additional flag evaluation options
     * @returns {T} Flag evaluation response
     */
    getNumberValue(flagKey: string, defaultValue: number, options?: FlagEvaluationOptions): number;
    getNumberValue<T extends number = number>(flagKey: string, defaultValue: T, options?: FlagEvaluationOptions): T;
    /**
     * Performs a flag evaluation that a returns an evaluation details object.
     * @param {string} flagKey The flag key uniquely identifies a particular flag
     * @template {number} T A optional generic argument constraining the number
     * @param {T} defaultValue The value returned if an error occurs
     * @param {FlagEvaluationOptions} options Additional flag evaluation options
     * @returns {Promise<EvaluationDetails<T>>} Flag evaluation details response
     */
    getNumberDetails(flagKey: string, defaultValue: number, options?: FlagEvaluationOptions): EvaluationDetails<number>;
    getNumberDetails<T extends number = number>(flagKey: string, defaultValue: T, options?: FlagEvaluationOptions): EvaluationDetails<T>;
    /**
     * Performs a flag evaluation that returns an object.
     * @param {string} flagKey The flag key uniquely identifies a particular flag
     * @template {JsonValue} T A optional generic argument describing the structure
     * @param {T} defaultValue The value returned if an error occurs
     * @param {FlagEvaluationOptions} options Additional flag evaluation options
     * @returns {Promise<T>} Flag evaluation response
     */
    getObjectValue(flagKey: string, defaultValue: JsonValue, options?: FlagEvaluationOptions): JsonValue;
    getObjectValue<T extends JsonValue = JsonValue>(flagKey: string, defaultValue: T, options?: FlagEvaluationOptions): T;
    /**
     * Performs a flag evaluation that a returns an evaluation details object.
     * @param {string} flagKey The flag key uniquely identifies a particular flag
     * @template {JsonValue} T A optional generic argument describing the structure
     * @param {T} defaultValue The value returned if an error occurs
     * @param {FlagEvaluationOptions} options Additional flag evaluation options
     * @returns {Promise<EvaluationDetails<T>>} Flag evaluation details response
     */
    getObjectDetails(flagKey: string, defaultValue: JsonValue, options?: FlagEvaluationOptions): EvaluationDetails<JsonValue>;
    getObjectDetails<T extends JsonValue = JsonValue>(flagKey: string, defaultValue: T, options?: FlagEvaluationOptions): EvaluationDetails<T>;
}

type Hook = BaseHook<FlagValue, void, void>;

/**
 * Interface that providers must implement to resolve flag values for their particular
 * backend or vendor.
 *
 * Implementation for resolving all the required flag types must be defined.
 */
interface Provider extends CommonProvider<ClientProviderStatus> {
    /**
     * A provider hook exposes a mechanism for provider authors to register hooks
     * to tap into various stages of the flag evaluation lifecycle. These hooks can
     * be used to perform side effects and mutate the context for purposes of the
     * provider. Provider hooks are not configured or controlled by the application author.
     */
    readonly hooks?: Hook[];
    /**
     * A handler function to reconcile changes made to the static context.
     * Called by the SDK when the context is changed.
     *
     * Returning a promise will put the provider in the RECONCILING state and
     * emit the ProviderEvents.Reconciling event.
     *
     * Return void will avoid putting the provider in the RECONCILING state and
     * **not** emit the ProviderEvents.Reconciling event.
     * @param oldContext
     * @param newContext
     */
    onContextChange?(oldContext: EvaluationContext, newContext: EvaluationContext): Promise<void> | void;
    /**
     * Resolve a boolean flag and its evaluation details.
     */
    resolveBooleanEvaluation(flagKey: string, defaultValue: boolean, context: EvaluationContext, logger: Logger): ResolutionDetails<boolean>;
    /**
     * Resolve a string flag and its evaluation details.
     */
    resolveStringEvaluation(flagKey: string, defaultValue: string, context: EvaluationContext, logger: Logger): ResolutionDetails<string>;
    /**
     * Resolve a numeric flag and its evaluation details.
     */
    resolveNumberEvaluation(flagKey: string, defaultValue: number, context: EvaluationContext, logger: Logger): ResolutionDetails<number>;
    /**
     * Resolve and parse an object flag and its evaluation details.
     */
    resolveObjectEvaluation<T extends JsonValue>(flagKey: string, defaultValue: T, context: EvaluationContext, logger: Logger): ResolutionDetails<T>;
}

/**
 * The No-op provider is set by default, and simply always returns the default value.
 */
declare class NoopFeatureProvider implements Provider {
    readonly metadata: {
        readonly name: "No-op Provider";
    };
    resolveBooleanEvaluation(_: string, defaultValue: boolean): ResolutionDetails<boolean>;
    resolveStringEvaluation(_: string, defaultValue: string): ResolutionDetails<string>;
    resolveNumberEvaluation(_: string, defaultValue: number): ResolutionDetails<number>;
    resolveObjectEvaluation<T extends JsonValue>(_: string, defaultValue: T): ResolutionDetails<T>;
    private noOp;
}
declare const NOOP_PROVIDER: NoopFeatureProvider;

/**
 * Minimal `EventEmitter` interface that is molded against the Node.js
 * `EventEmitter` interface.
 */
declare class EventEmitter<
  EventTypes extends EventEmitter.ValidEventTypes = string | symbol,
  Context extends any = any
> {
  static prefixed: string | boolean;

  /**
   * Return an array listing the events for which the emitter has registered
   * listeners.
   */
  eventNames(): Array<EventEmitter.EventNames<EventTypes>>;

  /**
   * Return the listeners registered for a given event.
   */
  listeners<T extends EventEmitter.EventNames<EventTypes>>(
    event: T
  ): Array<EventEmitter.EventListener<EventTypes, T>>;

  /**
   * Return the number of listeners listening to a given event.
   */
  listenerCount(event: EventEmitter.EventNames<EventTypes>): number;

  /**
   * Calls each of the listeners registered for a given event.
   */
  emit<T extends EventEmitter.EventNames<EventTypes>>(
    event: T,
    ...args: EventEmitter.EventArgs<EventTypes, T>
  ): boolean;

  /**
   * Add a listener for a given event.
   */
  on<T extends EventEmitter.EventNames<EventTypes>>(
    event: T,
    fn: EventEmitter.EventListener<EventTypes, T>,
    context?: Context
  ): this;
  addListener<T extends EventEmitter.EventNames<EventTypes>>(
    event: T,
    fn: EventEmitter.EventListener<EventTypes, T>,
    context?: Context
  ): this;

  /**
   * Add a one-time listener for a given event.
   */
  once<T extends EventEmitter.EventNames<EventTypes>>(
    event: T,
    fn: EventEmitter.EventListener<EventTypes, T>,
    context?: Context
  ): this;

  /**
   * Remove the listeners of a given event.
   */
  removeListener<T extends EventEmitter.EventNames<EventTypes>>(
    event: T,
    fn?: EventEmitter.EventListener<EventTypes, T>,
    context?: Context,
    once?: boolean
  ): this;
  off<T extends EventEmitter.EventNames<EventTypes>>(
    event: T,
    fn?: EventEmitter.EventListener<EventTypes, T>,
    context?: Context,
    once?: boolean
  ): this;

  /**
   * Remove all listeners, or those of the specified event.
   */
  removeAllListeners(event?: EventEmitter.EventNames<EventTypes>): this;
}

declare namespace EventEmitter {
  export interface ListenerFn<Args extends any[] = any[]> {
    (...args: Args): void;
  }

  export interface EventEmitterStatic {
    new <
      EventTypes extends ValidEventTypes = string | symbol,
      Context = any
    >(): EventEmitter<EventTypes, Context>;
  }

  /**
   * `object` should be in either of the following forms:
   * ```
   * interface EventTypes {
   *   'event-with-parameters': any[]
   *   'event-with-example-handler': (...args: any[]) => void
   * }
   * ```
   */
  export type ValidEventTypes = string | symbol | object;

  export type EventNames<T extends ValidEventTypes> = T extends string | symbol
    ? T
    : keyof T;

  export type ArgumentMap<T extends object> = {
    [K in keyof T]: T[K] extends (...args: any[]) => void
      ? Parameters<T[K]>
      : T[K] extends any[]
      ? T[K]
      : any[];
  };

  export type EventListener<
    T extends ValidEventTypes,
    K extends EventNames<T>
  > = T extends string | symbol
    ? (...args: any[]) => void
    : (
        ...args: ArgumentMap<Exclude<T, string | symbol>>[Extract<K, keyof T>]
      ) => void;

  export type EventArgs<
    T extends ValidEventTypes,
    K extends EventNames<T>
  > = Parameters<EventListener<T, K>>;

  export const EventEmitter: EventEmitterStatic;
}

/**
 * A subset of events that can be directly emitted by providers.
 */
type ProviderEmittableEvents = Exclude<ClientProviderEvents, ClientProviderEvents.ContextChanged>;

/**
 * The OpenFeatureEventEmitter can be used by provider developers to emit
 * events at various parts of the provider lifecycle.
 *
 * NOTE: Ready and error events are automatically emitted by the SDK based on
 * the result of the initialize method.
 */
declare class OpenFeatureEventEmitter extends GenericEventEmitter<ProviderEmittableEvents> {
    protected readonly eventEmitter: EventEmitter<string | symbol, any>;
    constructor();
}

/**
 * Don't export types from this file publicly.
 * It might cause confusion since these types are not a part of the general API,
 * but just for the in-memory provider.
 */

type Variants<T> = Record<string, T>;
/**
 * A Feature Flag definition, containing it's specification
 */
type Flag = {
    /**
     * An object containing all possible flags mappings (variant -> flag value)
     */
    variants: Variants<boolean> | Variants<string> | Variants<number> | Variants<JsonValue>;
    /**
     * The variant it will resolve to in STATIC evaluation
     */
    defaultVariant: string;
    /**
     * Determines if flag evaluation is enabled or not for this flag.
     * If false, falls back to the default value provided to the client
     */
    disabled: boolean;
    /**
     * Function used in order to evaluate a flag to a specific value given the provided context.
     * It should return a variant key.
     * If it does not return a valid variant it falls back to the default value provided to the client
     * @param EvaluationContext
     */
    contextEvaluator?: (ctx: EvaluationContext) => string;
};
type FlagConfiguration = Record<string, Flag>;

/**
 * A simple OpenFeature provider intended for demos and as a test stub.
 */
declare class InMemoryProvider implements Provider {
    readonly events: OpenFeatureEventEmitter;
    readonly runsOn = "client";
    readonly metadata: {
        readonly name: "in-memory";
    };
    private _flagConfiguration;
    private _context;
    constructor(flagConfiguration?: FlagConfiguration);
    /**
     * Overwrites the configured flags.
     * @param { FlagConfiguration } flagConfiguration new flag configuration
     */
    putConfiguration(flagConfiguration: FlagConfiguration): Promise<void>;
    resolveBooleanEvaluation(flagKey: string, defaultValue: boolean, context?: EvaluationContext, logger?: Logger): ResolutionDetails<boolean>;
    resolveNumberEvaluation(flagKey: string, defaultValue: number, context?: EvaluationContext, logger?: Logger): ResolutionDetails<number>;
    resolveStringEvaluation(flagKey: string, defaultValue: string, context?: EvaluationContext, logger?: Logger): ResolutionDetails<string>;
    resolveObjectEvaluation<T extends JsonValue>(flagKey: string, defaultValue: T, context?: EvaluationContext, logger?: Logger): ResolutionDetails<T>;
    private resolveAndCheckFlag;
    private resolveFlagWithReason;
    private lookupFlagValue;
}

interface Tracking {
    /**
     * Track a user action or application state, usually representing a business objective or outcome.
     * @param trackingEventName an identifier for the event
     * @param trackingEventDetails the details of the tracking event
     */
    track(trackingEventName: string, trackingEventDetails?: TrackingEventDetails): void;
}

interface Client extends EvaluationLifeCycle<Client>, Features, ManageLogger<Client>, Eventing<ClientProviderEvents>, Tracking {
    readonly metadata: ClientMetadata;
    /**
     * Returns the status of the associated provider.
     */
    readonly providerStatus: ClientProviderStatus;
}

declare class OpenFeatureAPI extends OpenFeatureCommonAPI<ClientProviderStatus, Provider, Hook> implements ManageContext<Promise<void>> {
    protected _statusEnumType: typeof ClientProviderStatus;
    protected _apiEmitter: GenericEventEmitter<ClientProviderEvents>;
    protected _defaultProvider: ProviderWrapper<Provider, ClientProviderStatus>;
    protected _domainScopedProviders: Map<string, ProviderWrapper<Provider, ClientProviderStatus>>;
    protected _createEventEmitter: () => OpenFeatureEventEmitter;
    private constructor();
    /**
     * Gets a singleton instance of the OpenFeature API.
     * @ignore
     * @returns {OpenFeatureAPI} OpenFeature API
     */
    static getInstance(): OpenFeatureAPI;
    private getProviderStatus;
    /**
     * Sets the default provider for flag evaluations and returns a promise that resolves when the provider is ready.
     * This provider will be used by domainless clients and clients associated with domains to which no provider is bound.
     * Setting a provider supersedes the current provider used in new and existing unbound clients.
     * @param {Provider} provider The provider responsible for flag evaluations.
     * @returns {Promise<void>}
     * @throws Uncaught exceptions thrown by the provider during initialization.
     */
    setProviderAndWait(provider: Provider): Promise<void>;
    /**
     * Sets the default provider for flag evaluations and returns a promise that resolves when the provider is ready.
     * This provider will be used by domainless clients and clients associated with domains to which no provider is bound.
     * Setting a provider supersedes the current provider used in new and existing unbound clients.
     * @param {Provider} provider The provider responsible for flag evaluations.
     * @param {EvaluationContext} context The evaluation context to use for flag evaluations.
     * @returns {Promise<void>}
     * @throws Uncaught exceptions thrown by the provider during initialization.
     */
    setProviderAndWait(provider: Provider, context: EvaluationContext): Promise<void>;
    /**
     * Sets the provider that OpenFeature will use for flag evaluations on clients bound to the same domain.
     * A promise is returned that resolves when the provider is ready.
     * Setting a provider supersedes the current provider used in new and existing clients bound to the same domain.
     * @param {string} domain The name to identify the client
     * @param {Provider} provider The provider responsible for flag evaluations.
     * @returns {Promise<void>}
     * @throws Uncaught exceptions thrown by the provider during initialization.
     */
    setProviderAndWait(domain: string, provider: Provider): Promise<void>;
    /**
     * Sets the provider that OpenFeature will use for flag evaluations on clients bound to the same domain.
     * A promise is returned that resolves when the provider is ready.
     * Setting a provider supersedes the current provider used in new and existing clients bound to the same domain.
     * @param {string} domain The name to identify the client
     * @param {Provider} provider The provider responsible for flag evaluations.
     * @param {EvaluationContext} context The evaluation context to use for flag evaluations.
     * @returns {Promise<void>}
     * @throws Uncaught exceptions thrown by the provider during initialization.
     */
    setProviderAndWait(domain: string, provider: Provider, context: EvaluationContext): Promise<void>;
    /**
     * Sets the default provider for flag evaluations.
     * This provider will be used by domainless clients and clients associated with domains to which no provider is bound.
     * Setting a provider supersedes the current provider used in new and existing unbound clients.
     * @param {Provider} provider The provider responsible for flag evaluations.
     * @returns {this} OpenFeature API
     */
    setProvider(provider: Provider): this;
    /**
     * Sets the default provider and evaluation context for flag evaluations.
     * This provider will be used by domainless clients and clients associated with domains to which no provider is bound.
     * Setting a provider supersedes the current provider used in new and existing unbound clients.
     * @param {Provider} provider The provider responsible for flag evaluations.
     * @param context {EvaluationContext} The evaluation context to use for flag evaluations.
     * @returns {this} OpenFeature API
     */
    setProvider(provider: Provider, context: EvaluationContext): this;
    /**
     * Sets the provider for flag evaluations of providers with the given name.
     * Setting a provider supersedes the current provider used in new and existing clients bound to the same domain.
     * @param {string} domain The name to identify the client
     * @param {Provider} provider The provider responsible for flag evaluations.
     * @returns {this} OpenFeature API
     */
    setProvider(domain: string, provider: Provider): this;
    /**
     * Sets the provider and evaluation context flag evaluations of providers with the given name.
     * Setting a provider supersedes the current provider used in new and existing clients bound to the same domain.
     * @param {string} domain The name to identify the client
     * @param {Provider} provider The provider responsible for flag evaluations.
     * @param context {EvaluationContext} The evaluation context to use for flag evaluations.
     * @returns {this} OpenFeature API
     */
    setProvider(domain: string, provider: Provider, context: EvaluationContext): this;
    /**
     * Sets the evaluation context globally.
     * This will be used by all providers that have not bound to a domain.
     * @param {EvaluationContext} context Evaluation context
     * @example
     * await OpenFeature.setContext({ region: "us" });
     */
    setContext(context: EvaluationContext): Promise<void>;
    /**
     * Sets the evaluation context for a specific provider.
     * This will only affect providers bound to a domain.
     * @param {string} domain An identifier which logically binds clients with providers
     * @param {EvaluationContext} context Evaluation context
     * @example
     * await OpenFeature.setContext("test", { scope: "provider" });
     * OpenFeature.setProvider(new MyProvider()) // Uses the default context
     * OpenFeature.setProvider("test", new MyProvider()) // Uses context: { scope: "provider" }
     */
    setContext(domain: string, context: EvaluationContext): Promise<void>;
    /**
     * Access the global evaluation context.
     * @returns {EvaluationContext} Evaluation context
     */
    getContext(): EvaluationContext;
    /**
     * Access the evaluation context for a specific named client.
     * The global evaluation context is returned if a matching named client is not found.
     * @param {string} domain An identifier which logically binds clients with providers
     * @returns {EvaluationContext} Evaluation context
     */
    getContext(domain?: string | undefined): EvaluationContext;
    /**
     * Resets the global evaluation context to an empty object.
     */
    clearContext(): Promise<void>;
    /**
     * Removes the evaluation context for a specific named client.
     * @param {string} domain An identifier which logically binds clients with providers
     */
    clearContext(domain: string): Promise<void>;
    /**
     * Resets the global evaluation context and removes the evaluation context for
     * all domains.
     */
    clearContexts(): Promise<void>;
    /**
     * A factory function for creating new named OpenFeature clients. Clients can contain
     * their own state (e.g. logger, hook, context). Multiple clients can be used
     * to segment feature flag configuration.
     *
     * If there is already a provider bound to this name via {@link this.setProvider setProvider}, this provider will be used.
     * Otherwise, the default provider is used until a provider is assigned to that name.
     * @param {string} domain An identifier which logically binds clients with providers
     * @param {string} version The version of the client (only used for metadata)
     * @returns {Client} OpenFeature Client
     */
    getClient(domain?: string, version?: string): Client;
    /**
     * Clears all registered providers and resets the default provider.
     * @returns {Promise<void>}
     */
    clearProviders(): Promise<void>;
    private runProviderContextChangeHandler;
}
/**
 * A singleton instance of the OpenFeature API.
 * @returns {OpenFeatureAPI} OpenFeature API
 */
declare const OpenFeature: OpenFeatureAPI;

export { type Client, type Features, type FlagEvaluationOptions, type Hook, InMemoryProvider, NOOP_PROVIDER, OpenFeature, OpenFeatureAPI, OpenFeatureEventEmitter, type Provider, type ProviderEmittableEvents, type Tracking };
