import { ObjectId } from 'mongodb';
import type { Join, KeysOfAType, OptionalId, WithId } from 'mongodb';
import type { DeepPick } from './DeepPick.ts';
import type { Hooks } from './hooks.ts';
import type { PaprBulkWriteOperation, PaprUpdateFilter } from './mongodbTypes.ts';
import type { DefaultsOption, SchemaOptions, SchemaTimestampOptions } from './schema.ts';
export declare enum VALIDATION_ACTIONS {
    ERROR = "error",
    WARN = "warn"
}
export declare enum VALIDATION_LEVEL {
    MODERATE = "moderate",
    OFF = "off",
    STRICT = "strict"
}
export interface BaseSchema {
    _id: ObjectId | number | string;
}
export type RequiredProperties<Properties> = {
    [Prop in keyof Properties]: undefined extends Properties[Prop] ? never : Prop;
}[keyof Properties];
export type OptionalProperties<Properties> = Exclude<keyof Properties, RequiredProperties<Properties>>;
export type ObjectType<Properties> = Flatten<Pick<Properties, NonNullable<RequiredProperties<Properties>>> & {
    [Prop in OptionalProperties<Properties>]?: Properties[Prop];
}>;
type TimestampSchemaProperty<TProperty extends keyof Exclude<SchemaTimestampOptions, boolean>, TOptions extends SchemaTimestampOptions | undefined> = TOptions extends object ? TOptions[TProperty] extends string ? TOptions[TProperty] : TProperty : TOptions extends false ? never : TProperty;
export type TimestampSchema<TOptions extends SchemaTimestampOptions | undefined> = Record<TimestampSchemaProperty<'createdAt', TOptions> | TimestampSchemaProperty<'updatedAt', TOptions>, Date>;
export interface ModelOptions {
    hooks?: Hooks;
    maxTime?: number;
}
export type DocumentForInsertWithoutDefaults<TSchema, TDefaults extends Partial<TSchema>> = Omit<OptionalId<TSchema>, keyof TDefaults> & Partial<Pick<TSchema, keyof TDefaults & keyof TSchema>>;
export type SchemaDefaultValues<TSchema, TOptions extends SchemaOptions<TSchema>> = TOptions['defaults'] extends () => infer ReturnDefaults ? Awaited<ReturnDefaults> : TOptions['defaults'];
export type DocumentForInsert<TSchema, TOptions extends SchemaOptions<TSchema>, TDefaults extends NonNullable<SchemaDefaultValues<TSchema, TOptions>> = NonNullable<SchemaDefaultValues<TSchema, TOptions>>> = TOptions['timestamps'] extends SchemaTimestampOptions ? TOptions['timestamps'] extends false ? DocumentForInsertWithoutDefaults<TSchema, TDefaults> : Omit<DocumentForInsertWithoutDefaults<TSchema, TDefaults>, keyof TimestampSchema<TOptions['timestamps']>> & Partial<TimestampSchema<TOptions['timestamps']>> : DocumentForInsertWithoutDefaults<TSchema, TDefaults>;
type Identity<Type> = Type;
type Flatten<Type extends object> = Identity<{
    [Key in keyof Type]: Type[Key];
}>;
/**
 * Returns tuple of strings (keys to be joined on '.') that represent every path into a schema
 *
 * https://docs.mongodb.com/manual/tutorial/query-embedded-documents/
 *
 * @remarks
 * Through testing we determined that a depth of 6 is safe for the typescript compiler
 * and provides reasonable compilation times. This number is otherwise not special and
 * should be changed if issues are found with this level of checking. Beyond this
 * depth any helpers that make use of NestedPaths should devolve to not asserting any
 * type safety on the input.
 */
export type NestedPaths<Type, Depth extends number[]> = Depth['length'] extends 6 ? [] : Type extends Buffer | Date | RegExp | Uint8Array | boolean | number | string | ((...args: any[]) => any) | {
    _bsontype: string;
} ? [] : Type extends readonly (infer ArrayType)[] ? [...NestedPaths<ArrayType, [...Depth, 1]>] | [] | [number, ...NestedPaths<ArrayType, [...Depth, 1]>] | [number] : Type extends Map<string, any> ? [string] : Type extends object ? {
    [Key in Extract<keyof Type, string>]: Type[Key] extends readonly any[] ? [Key, ...NestedPaths<Type[Key], [...Depth, 1]>] : [Key, ...NestedPaths<Type[Key], [...Depth, 1]>] | [Key];
}[Extract<keyof Type, string>] : [];
type FilterProperties<TObject, TValue> = Pick<TObject, KeysOfAType<TObject, TValue>>;
export type ProjectionType<TSchema extends BaseSchema, Projection extends Partial<Record<Join<NestedPaths<WithId<TSchema>, []>, '.'>, number>> | undefined> = undefined extends Projection ? WithId<TSchema> : keyof FilterProperties<Projection, 0 | 1> extends never ? WithId<DeepPick<TSchema, '_id' | (string & keyof Projection)>> : keyof FilterProperties<Projection, 1> extends never ? Omit<WithId<TSchema>, keyof FilterProperties<Projection, 0>> : Omit<WithId<DeepPick<TSchema, '_id' | (string & keyof Projection)>>, keyof FilterProperties<Projection, 0>>;
export type Projection<TSchema> = Partial<Record<Join<NestedPaths<WithId<TSchema>, []>, '.'>, number>>;
export type PropertyNestedType<Type, Property extends string> = Property extends `${infer Key}.${infer Rest}` ? Key extends `${number}` ? NonNullable<Type> extends readonly (infer ArrayType)[] ? PropertyType<ArrayType, Rest> : unknown : Key extends keyof Type ? Type[Key] extends Map<string, infer MapType> ? MapType : PropertyType<NonNullable<Type[Key]>, Rest> : unknown : unknown;
export type PropertyType<Type, Property extends string> = string extends Property ? unknown : Property extends keyof Type ? Type extends Record<string, any> ? Property extends `${string}.${string}` ? PropertyNestedType<NonNullable<Type>, Property> : Type[Property] : Type[Property] : Type extends readonly (infer ArrayType)[] ? Property extends `${number}` ? ArrayType : Property extends keyof ArrayType ? PropertyType<ArrayType, Property> : PropertyNestedType<NonNullable<Type>, Property> : PropertyNestedType<NonNullable<Type>, Property>;
export type RequireAtLeastOne<TObj, Keys extends keyof TObj = keyof TObj> = {
    [Key in Keys]-?: Partial<Pick<TObj, Exclude<Keys, Key>>> & Required<Pick<TObj, Key>>;
}[Keys] & Pick<TObj, Exclude<keyof TObj, Keys>>;
export declare function getIds(ids: Set<string> | readonly (ObjectId | string)[]): ObjectId[];
/**
 * @module intro
 * @description
 *
 * ## `DocumentForInsert`
 *
 * This TypeScript type is useful to define an document representation for an insertion operation, where the `_id` and
 * other properties which have defaults defined are not required.
 *
 * ```ts
 * import { DocumentForInsert } from 'papr';
 *
 * import type { OrderDocument, OrderOptions } from './schema';
 *
 * const newOrder: DocumentForInsert<OrderDocument, OrderOptions> = {
 *   user: 'John',
 * };
 *
 * newOrder._id; // ObjectId | undefined
 * newOrder.user; // string
 * newOrder.product; // string | undefined
 * ```
 *
 * ## `ProjectionType`
 *
 * This TypeScript type is useful to compute the sub-document resulting from a `find*` operation which used a projection.
 *
 * ```ts
 * import { ProjectionType } from 'papr';
 *
 * const projection = {
 *   firstName: 1
 * };
 *
 * type UserProjected = ProjectionType<UserDocument, typeof projection>;
 *
 * const user: UserProjected = await User.findOne({}, { projection });
 *
 * user?._id; // value
 * user?.firstName; // value
 * user?.lastName; // TypeScript error
 * user?.age; // TypeScript error
 * ```
 *
 * When this type is used in conjunction with `as const`, it allows projections with excluding fields.
 *
 * ```ts
 * import { ProjectionType } from 'papr';
 *
 * const projection = {
 *   firstName: 0,
 * } as const;
 *
 * type UserProjected = ProjectionType<UserDocument, typeof projection>;
 *
 * const user: UserProjected = await User.findOne({}, { projection });
 *
 * user?._id; // value
 * user?.firstName; // TypeScript error
 * user?.lastName; // value
 * user?.age; // value
 * ```
 *
 * ## `VALIDATION_ACTIONS`
 *
 * ```ts
 * enum VALIDATION_ACTIONS {
 *   ERROR = 'error',
 *   WARN = 'warn',
 * }
 * ```
 *
 * ## `VALIDATION_LEVEL`
 *
 * ```ts
 * enum VALIDATION_LEVEL {
 *   MODERATE = 'moderate',
 *   OFF = 'off',
 *   STRICT = 'strict',
 * }
 * ```
 */
export declare function getDefaultValues<TSchema extends BaseSchema>(defaults?: DefaultsOption<TSchema>): Promise<Partial<TSchema>>;
export declare function getTimestampProperty<TProperty extends keyof Exclude<SchemaTimestampOptions, boolean>, TOptions extends SchemaTimestampOptions | undefined>(property: TProperty, options: TOptions): keyof Exclude<SchemaTimestampOptions, boolean>;
export declare function timestampUpdateFilter<TSchema, TOptions extends SchemaOptions<TSchema>>(update: PaprUpdateFilter<TSchema>, timestamps: TOptions['timestamps']): PaprUpdateFilter<TSchema>;
export declare function timestampBulkWriteOperation<TSchema, TOptions extends SchemaOptions<TSchema>>(operation: PaprBulkWriteOperation<TSchema, TOptions>, timestamps: TOptions['timestamps']): PaprBulkWriteOperation<TSchema, TOptions>;
export declare function cleanSetOnInsert<TSchema>($setOnInsert: Record<string, unknown>, update: PaprUpdateFilter<TSchema>): NonNullable<PaprUpdateFilter<TSchema>['$setOnInsert']>;
export {};
