import { RestModel } from './restmodels';
import BasicRestModel from './restmodels/basic/BasicRestModel';
import BasicIdRestModel from './restmodels/basic/BasicIdRestModel';
export declare type StringOrNumberKeys<T> = {
    [P in keyof T]: T[P] extends (string | number) ? P : never;
}[keyof T];
export declare type Item = {
    [key: string]: ItemFieldType;
};
declare type OptionalFields<T extends Item> = {
    [P in keyof T]: T[P] extends {
        type: any;
        required: true;
    } ? never : T[P] extends [{
        type: any;
        required: true;
    }] ? never : P;
}[keyof T];
declare type Optional<T, K extends keyof T> = Omit<T, K> & Partial<T>;
export declare type ItemFieldWithParams<T> = {
    type: T;
    required?: true | false;
    nullable?: true | false;
};
export declare type ModelItemFieldWithParams = {
    type: RestModel<any>;
    required?: true | false;
    nullable?: true | false;
    idOnly?: true | false;
};
export declare type ItemFieldType<T = false> = ItemFieldBasicType<T> | [ItemFieldBasicType<T>] | ModelItemFieldWithParams | [ModelItemFieldWithParams] | ItemFieldWithParams<ItemFieldBasicType> | [ItemFieldWithParams<ItemFieldBasicType<T>>] | ItemFieldWithParams<ItemFieldBasicType<T>>[];
export declare type ItemFieldBasicType<T = false> = StringConstructor | BooleanConstructor | NumberConstructor | Schema<any> | RestModel<any> | (T extends true ? any : never);
export declare type IdPopulatedType<PopulatedType, IdKey extends keyof PopulatedType> = {
    [f in IdKey]: PopulatedType[IdKey];
} & Partial<PopulatedType>;
declare type CommonFieldType<arg> = arg extends StringConstructor ? string : arg extends BooleanConstructor ? boolean : arg extends NumberConstructor ? number : arg extends DateConstructor ? Date : arg;
export declare type PopulatedTypeField<arg extends Item['']> = arg extends {
    type: any;
    nullable: true;
} ? PopulatedArrayRealTypeField<arg> | null : PopulatedArrayRealTypeField<arg>;
declare type PopulatedArrayRealTypeField<arg> = arg extends [infer c] ? GetPopulatedTypeField<c>[] : GetPopulatedTypeField<arg>;
declare type FullPopulatedTypeField<arg extends Item['']> = arg extends {
    type: any;
    nullable: true;
} ? FullPopulatedArrayRealTypeField<arg> | null : FullPopulatedArrayRealTypeField<arg>;
declare type FullPopulatedArrayRealTypeField<arg> = arg extends [infer c] ? GetFullPopulatedTypeField<c>[] : GetFullPopulatedTypeField<arg>;
declare type GetPopulatedTypeField<arg> = arg extends {
    type: infer c;
} ? arg extends {
    type: infer c;
    idOnly: true;
} ? GetBasicPopulatedTypeField<c> : GetBasicPopulatedTypeField<c, true> : GetBasicPopulatedTypeField<arg>;
declare type GetFullPopulatedTypeField<arg> = arg extends {
    type: infer c;
} ? GetBasicFullPopulatedTypeField<c> : GetBasicFullPopulatedTypeField<arg>;
declare type GetBasicFullPopulatedTypeField<arg> = arg extends BasicRestModel<infer S, infer Id> ? S['FullPopulatedType'] : arg extends BasicIdRestModel<infer S, infer Id> ? S['FullPopulatedType'] : arg extends Schema<any, any, infer FullPopulatedType> ? FullPopulatedType : CommonFieldType<arg>;
declare type GetBasicPopulatedTypeField<arg, idOnly = false> = idOnly extends true ? (arg extends BasicRestModel<infer S, infer Id> ? S['PopulatedType'] : arg extends BasicIdRestModel<infer S, infer Id> ? S['PopulatedType'] : arg extends Schema<any, infer PopulatedType> ? PopulatedType : CommonFieldType<arg>) : (arg extends BasicRestModel<infer S, infer Id> ? IdPopulatedType<S['PopulatedType'], Id> : arg extends BasicIdRestModel<infer S, infer Id> ? IdPopulatedType<S['PopulatedType'], Id> : arg extends Schema<any, infer PopulatedType> ? PopulatedType : CommonFieldType<arg>);
export declare type RealTypeField<arg extends ItemFieldType<any>> = arg extends {
    type: any;
    nullable: true;
} ? ArrayRealTypeField<arg> | null : ArrayRealTypeField<arg>;
declare type ArrayRealTypeField<arg> = arg extends [infer c] ? GetRealTypeField<c>[] : GetRealTypeField<arg>;
declare type GetRealTypeField<arg> = arg extends {
    type: infer c;
} ? arg extends {
    type: infer c;
    idOnly: true;
} ? GetBasicRealTypeField<c> : GetBasicRealTypeField<c, true> : GetBasicRealTypeField<arg>;
declare type GetBasicRealTypeField<arg, idOnly = false> = idOnly extends true ? (arg extends BasicRestModel<infer S, infer Id> ? S['RealType'] : arg extends BasicIdRestModel<infer S, infer Id> ? S['RealType'] : arg extends Schema<infer RealType, infer d> ? {
    [k in keyof RealType]: RealType[k];
} : CommonFieldType<arg>) : (arg extends BasicRestModel<infer S, infer Id> ? S['RealType'][Id] : arg extends BasicIdRestModel<infer S, infer Id> ? S['RealType'][Id] : arg extends Schema<infer RealType, infer d> ? RealType : CommonFieldType<arg>);
export declare type SchemaFullPopulatedType<T extends Item> = keyof T extends never ? {} : OptionalFields<T> extends never ? {
    -readonly [P in keyof T]: FullPopulatedTypeField<T[P]>;
} : Optional<{
    -readonly [P in keyof T]: FullPopulatedTypeField<T[P]>;
}, OptionalFields<T>>;
export declare type SchemaPopulatedType<T extends Item> = keyof T extends never ? {} : OptionalFields<T> extends never ? {
    -readonly [P in keyof T]: PopulatedTypeField<T[P]>;
} : Optional<{
    -readonly [P in keyof T]: PopulatedTypeField<T[P]>;
}, OptionalFields<T>>;
export declare type SchemaRealType<T extends Item> = keyof T extends never ? {} : OptionalFields<T> extends never ? {
    -readonly [P in keyof T]: RealTypeField<T[P]>;
} : Optional<{
    -readonly [P in keyof T]: RealTypeField<T[P]>;
}, OptionalFields<T>>;
export declare function fieldIsSchema(property: any): property is Schema<any>;
export declare type DeleteFieldSchema<T> = {
    0: T;
} & Array<T>;
export declare type SchemaWithoutKeys<S extends Schema<any>, K extends DeleteFieldSchema<keyof S['RealType']>> = Schema<{
    [K2 in Exclude<keyof S['RealType'], K[number]>]: S['RealType'][K2];
}, {
    [K2 in Exclude<keyof S['PopulatedType'], K[number]>]: S['PopulatedType'][K2];
}, {
    [K2 in Exclude<keyof S['FullPopulatedType'], K[number]>]: S['FullPopulatedType'][K2];
}>;
interface DeleteFieldsType<S extends Schema<any>> {
    <K extends DeleteFieldSchema<keyof S['RealType']>>(...keys: K): Schema<{
        [K2 in Exclude<keyof S['RealType'], K[number]>]: S['RealType'][K2];
    }, {
        [K2 in Exclude<keyof S['PopulatedType'], K[number]>]: S['PopulatedType'][K2];
    }, {
        [K2 in Exclude<keyof S['FullPopulatedType'], K[number]>]: S['FullPopulatedType'][K2];
    }>;
}
interface UpdateFieldsType<RT extends object, PT extends object, FPT extends object> {
    <I extends Item>(newSchema: I): Schema<{
        [K2 in keyof RT | keyof I]: K2 extends keyof RT ? RT[K2] : K2 extends keyof I ? SchemaRealType<Pick<I, K2>>[keyof SchemaRealType<Pick<I, K2>>] : never;
    }, {
        [K2 in keyof PT | keyof I]: K2 extends keyof PT ? PT[K2] : K2 extends keyof I ? SchemaPopulatedType<Pick<I, K2>>[keyof SchemaPopulatedType<Pick<I, K2>>] : never;
    }, {
        [K2 in keyof FPT | keyof I]: K2 extends keyof FPT ? FPT[K2] : K2 extends keyof I ? SchemaFullPopulatedType<Pick<I, K2>>[keyof SchemaFullPopulatedType<Pick<I, K2>>] : never;
    }>;
}
export declare class Schema<RealType extends {
    [key: string]: any;
} = any, PopulatedType extends {
    [key: string]: any;
} = any, FullPopulatedType extends {
    [key: string]: any;
} = any> {
    readonly _schema: Item;
    readonly _subSchema?: Schema<any>;
    private functionToConvert?;
    constructor(schema: Item, subSchema?: Schema<any>);
    get RealType(): RealType;
    get PopulatedType(): PopulatedType;
    get FullPopulatedType(): FullPopulatedType;
    static getSchema<I extends Item>(schema: I): Schema<SchemaRealType<I>, SchemaPopulatedType<I>, SchemaFullPopulatedType<I>>;
    protected _fieldIsAnIdModel(property: ItemFieldType): property is BasicIdRestModel;
    private fieldIsExtendedFormatWithModel;
    protected fieldIsSchema(property: ItemFieldType): property is Schema<any>;
    private isItemFromProperty;
    private getErrorFromItemProperty;
    private get keys();
    updateSchema: UpdateFieldsType<RealType, PopulatedType, FullPopulatedType>;
    deleteFields: DeleteFieldsType<this>;
    /**
     *
     * @param f field to update
     * @param fx function in order to convert the field
     */
    updateField<Field extends keyof RealType, ReturnType>(f: Field, fx: (value: RealType[Field]) => ReturnType): Schema<{
        [K2 in keyof RealType]: K2 extends Field ? ReturnType : RealType[K2];
    }, {
        [K2 in keyof PopulatedType]: K2 extends Field ? ReturnType : PopulatedType[K2];
    }, {
        [K2 in keyof FullPopulatedType]: K2 extends Field ? ReturnType : FullPopulatedType[K2];
    }>;
    _getModelValuesToPopulate(item: RealType, callback: (model: BasicIdRestModel, id: any) => void): void;
    validate(str: any): str is RealType;
    private getValidateError;
    getValidateErrorPretty(str: any): string;
    getValidateArrayError(str: any): any;
    validateArray(str: any): str is RealType[];
}
declare const _default: typeof Schema.getSchema;
export default _default;
