import { Overrides, ReservedInputParameterNames } from '../util';
/**
 * Type for the overrides object that is either hardcoded in the adapter,
 * or present in the incoming request body
 */
export type Override = Map<string, Map<string, string>>;
/**
 * Possible strings that correspond to types of primitive values
 * that can be specified for an input parameter
 */
type PrimitiveParameterTypeString = 'boolean' | 'number' | 'string';
/**
 * Possible types for each of the possible type strings
 */
type PrimitiveParameterType = TypeFromTypeString<PrimitiveParameterTypeString>;
/**
 * All possible types for an input parameter (either a string, or a nested param definition)
 */
type ParameterType = PrimitiveParameterTypeString | InputParametersDefinition;
/**
 * Given a type parameter T that is a parameter type (string or nested definition),
 * equals to the corresponding type for that type string or definition
 */
type TypeFromTypeString<T extends ParameterType> = T extends 'string' ? string : T extends 'number' ? number : T extends 'boolean' ? boolean : T extends InputParametersDefinition ? TypeFromDefinition<T> : never;
/**
 * All posible types for specifying options for an InputParameter
 */
type ParameterOptions = string[] | readonly string[] | number[] | readonly number[];
/**
 * Given a parameter P, if the parameter has options it will constrain the type to a union of those options.
 */
type TypeFromOptionsOrTypeString<P extends InputParameter> = P['options'] extends ParameterOptions ? P['options'][number] : TypeFromTypeString<P['type']>;
/**
 * Util type to be able to discern exactly if a generic is exactly unknown
 * (because everything extends unknown, but unknown only extends itself)
 */
type IsUnknown<T> = unknown extends T ? true : false;
/**
 * Given a concrete InputParameter P, results in the type for that definition taking into account
 * the required property of the definition (i.e. makes it optional or not)
 */
type ShouldBeUndefinable<P extends InputParameter, T = TypeFromOptionsOrTypeString<P>> = P['required'] extends true ? T : IsUnknown<P['default']> extends true ? T | undefined : T;
/**
 * Just an alias to make types below more readable
 */
type NonArrayInputType<P extends InputParameter> = ShouldBeUndefinable<P>;
/**
 * Given an InputParameter P, results in the corresponding type for that definition,
 * accounting for configurations like required, array, defaults, etc.
 */
type TypeFromParameter<P extends InputParameter, T = NonArrayInputType<P>> = P['array'] extends true ? Exclude<T, undefined>[] : T;
/**
 * Constraint for an InputParameter to make sure options are only specified for parameters of type string.
 * All these constraints, for them to work properly, should represent the entire closed realm of possibilities.
 * That is, there should be no possible input parameter that the constraint doesn't accept one way or the other.
 */
type InputParameterOptionConstraints = {
    type: 'string';
    options?: string[] | readonly string[];
} | {
    type: 'number';
    options?: number[] | readonly number[];
} | {
    type: Exclude<ParameterType, 'string' | 'number'>;
    options?: never;
};
/**
 * Constraint to make sure input parameter defaults match their type, and that
 * defaults are only allowed for primitive types
 */
type InputParameterDefaultTypeConstraints = {
    type: 'string';
    default?: string;
} | {
    type: 'number';
    default?: number;
} | {
    type: 'boolean';
    default?: boolean;
} | {
    type: Exclude<ParameterType, 'string' | 'number' | 'boolean'>;
    default?: never;
};
/**
 * Constraint to avoid unnecessary or impossible required and default combinations
 */
type InputParameterDefaultRequiredConstraints = {
    required: true;
    default?: never;
} | {
    required?: false;
    default?: PrimitiveParameterType;
};
/**
 * Constraint to make sure array input parameters don't specify a default
 */
type InputParameterArrayDefaultConstraints = {
    array: true;
    default?: never;
} | {
    array?: false;
    default?: PrimitiveParameterType;
};
/**
 * Basic structure for an InputParameter.
 * The concrete possible types that will be used in a definition can be found below this one.
 * (they are split into several types due to existential types not being supported)
 */
type BaseInputParameter = {
    description: string;
    type: ParameterType;
    default?: PrimitiveParameterType;
    required?: boolean;
    array?: boolean;
    options?: ParameterOptions;
    aliases?: readonly string[];
    dependsOn?: readonly string[];
    exclusive?: readonly string[];
};
/**
 * Type for the definition of one InputParameter.
 * This is built from the base type, intersected with a bunch of constraints.
 */
export type InputParameter = BaseInputParameter & InputParameterOptionConstraints & InputParameterDefaultTypeConstraints & InputParameterDefaultRequiredConstraints & InputParameterArrayDefaultConstraints;
/**
 * Map of input names to their corresponding definition.
 */
export type InputParametersDefinition = Record<string, InputParameter>;
/**
 * Constrains the InputParametersDefinition to exclude reserved param names.
 */
type ProperInputParametersDefinition = InputParametersDefinition & {
    [K in ReservedInputParameterNames]?: never;
};
type EmptyDefinition = {};
/**
 * Given an input parameter definition, results in the type for the actual params object.
 *
 * The use of any is to avoid problems stemming from the heterogeneous array of [[AdapterEndpoint]]
 * in the [[AdapterParams]]. What we're doing is basically saying that if the definition provided to this
 * type is `any`, then the resulting type for that definition should be `any` as well.
 * For more details, please look at said `endpoints` param and the explanations there.
 */
export type TypeFromDefinition<T extends InputParametersDefinition> = unknown extends T ? any : {
    -readonly [K in keyof T as TypeFromDefinitionIsDefined<T[K]> extends true ? K : never]: TypeFromParameter<T[K]>;
} & {
    -readonly [K in keyof T as TypeFromDefinitionIsDefined<T[K]> extends true ? never : K]?: TypeFromParameter<T[K]>;
};
/**
 * Checks whether the definition for a single input parameter should include undefined in its options or not.
 * This is to discern while computing the type from input param definitions to make them optional keys as well.
 */
type TypeFromDefinitionIsDefined<T extends InputParameter> = T['required'] extends true ? true : T['array'] extends true ? true : IsUnknown<T['default']> extends false ? true : false;
/**
 * Util type to represent the absence of input parameters for an adapter endpoint.
 */
export type EmptyInputParameters = EmptyDefinition;
/**
 * This class encapsulates logic for a single input parameter, taking its definition
 * and performing validations (both on the definition on construction, and params when prompted).
 */
declare class ProcessedParam<const T extends InputParameter = InputParameter> {
    name: string;
    definition: T;
    /** List of aliases for this processed parameter, including the original parameter name */
    aliases: string[];
    /** Set of all possible options for this parameter (used when validating inputs) */
    options?: Set<TypeFromParameter<T>>;
    /** Definition for the type of this parameter */
    type: PrimitiveParameterTypeString | InputParameters<InputParametersDefinition>;
    constructor(name: string, definition: T);
    /** Util method to throw a definition error prefixed with this param name */
    private definitionError;
    /** Util method to throw a validation error prefixed with this param name */
    private validationError;
    /**
     * Validates the definition that this parameter has been constructed with.
     */
    private validateDefinition;
    /**
     * Validates an incoming adapter request's input params and
     * performs all necessary checks and modifications.
     *
     * @param input - the input data from an incoming adapter request
     * @returns - the validated data
     */
    validateInput(input: unknown): unknown;
    /**
     * Validates a single value from the incoming params.
     *
     * @param input - a single value from the request params object
     * @returns - the validated input data
     */
    private validateInputType;
}
export declare class InputParameters<const T extends ProperInputParametersDefinition> {
    definition: T;
    examples?: TypeFromDefinition<T>[] | undefined;
    readonly validated: TypeFromDefinition<T>;
    params: ProcessedParam[];
    constructor(definition: T, examples?: TypeFromDefinition<T>[] | undefined);
    /**
     * Validates the entire definitions object provided to the constructor.
     */
    private validateDefinition;
    /**
     * Validates an incoming adapter request's input params and
     * performs all necessary checks and modifications.
     *
     * @param input - the input data from an incoming adapter request
     * @returns - the validated data
     */
    validateInput(rawData: unknown): TypeFromDefinition<T>;
}
/**
 * Validates that the overrides object in a request (if present) is correct.
 *
 * @param input - a request's input data, which may contain overrides
 * @returns nothing, only throws if an error is found
 */
export declare const validateOverrides: (input: {
    overrides?: Overrides;
}) => void;
export {};
