import type { AlternativeType, ArrayElement, BitwiseFilter, BSONRegExp, BSONType, BSONTypeAlias, DeleteManyModel, DeleteOneModel, Document, IntegerType, Join, KeysOfAType, NumericType, OnlyFieldsOfType, PullAllOperator, PullOperator, PushOperator, ReplaceOneModel, SetFields, Timestamp, UpdateManyModel, UpdateOneModel, WithId } from 'mongodb';
import type { SchemaOptions } from './schema.ts';
import type { DocumentForInsert, NestedPaths, PropertyType } from './utils.ts';
export type PaprBulkWriteOperation<TSchema, TOptions extends SchemaOptions<TSchema>> = {
    deleteMany: Omit<DeleteManyModel<TSchema>, 'filter'> & {
        filter: PaprFilter<TSchema>;
    };
} | {
    deleteOne: Omit<DeleteOneModel<TSchema>, 'filter'> & {
        filter: PaprFilter<TSchema>;
    };
} | {
    replaceOne: Omit<ReplaceOneModel<TSchema>, 'filter'> & {
        filter: PaprFilter<TSchema>;
    };
} | {
    updateMany: Omit<UpdateManyModel<TSchema>, 'filter' | 'update'> & {
        filter: PaprFilter<TSchema>;
        update: PaprUpdateFilter<TSchema>;
    };
} | {
    updateOne: Omit<UpdateOneModel<TSchema>, 'filter' | 'update'> & {
        filter: PaprFilter<TSchema>;
        update: PaprUpdateFilter<TSchema>;
    };
} | {
    insertOne: {
        document: DocumentForInsert<TSchema, TOptions>;
    };
};
export type PaprFilter<TSchema> = Partial<WithId<TSchema>> | (PaprFilterConditions<WithId<TSchema>> & PaprRootFilterOperators<WithId<TSchema>>);
export type PaprFilterConditions<TSchema> = {
    [Property in Join<NestedPaths<TSchema, []>, '.'>]?: PaprCondition<PropertyType<TSchema, Property>>;
};
export interface PaprRootFilterOperators<TSchema> {
    $and?: PaprFilter<TSchema>[];
    $nor?: PaprFilter<TSchema>[];
    $or?: PaprFilter<TSchema>[];
    $expr?: Record<string, any>;
    $text?: {
        $search: string;
        $language?: string;
        $caseSensitive?: boolean;
        $diacriticSensitive?: boolean;
    };
    $where?: string | ((this: TSchema) => boolean);
    $comment?: Document | string;
}
export type PaprCondition<Type> = AlternativeType<Type> | PaprFilterOperators<AlternativeType<Type>>;
export interface PaprFilterOperators<TValue> {
    $eq?: TValue;
    $gt?: TValue;
    $gte?: TValue;
    $in?: readonly TValue[];
    $lt?: TValue;
    $lte?: TValue;
    $ne?: TValue;
    $nin?: readonly TValue[];
    $not?: TValue extends string ? PaprFilterOperators<TValue> | RegExp : PaprFilterOperators<TValue>;
    /**
     * When `true`, `$exists` matches the documents that contain the field,
     * including documents where the field value is null.
     */
    $exists?: boolean;
    $type?: BSONType | BSONTypeAlias;
    $expr?: Record<string, any>;
    $jsonSchema?: Record<string, any>;
    $mod?: TValue extends number ? [number, number] : never;
    $regex?: TValue extends string ? BSONRegExp | RegExp | string : never;
    $options?: TValue extends string ? string : never;
    $geoIntersects?: {
        $geometry: Document;
    };
    $geoWithin?: Document;
    $near?: Document;
    $nearSphere?: Document;
    $maxDistance?: number;
    $all?: TValue extends readonly any[] ? readonly any[] : never;
    $elemMatch?: TValue extends readonly any[] ? Document : never;
    $size?: TValue extends readonly any[] ? number : never;
    $bitsAllClear?: BitwiseFilter;
    $bitsAllSet?: BitwiseFilter;
    $bitsAnyClear?: BitwiseFilter;
    $bitsAnySet?: BitwiseFilter;
    $rand?: Record<string, never>;
}
/**
 * Returns all dot-notation properties of a schema with their corresponding types.
 *
 * @example
 * {
 *   foo: string;
 *   'nested.field': number;
 * }
 */
export type PaprAllProperties<TSchema> = {
    [Property in Join<NestedPaths<TSchema, []>, '.'>]?: PropertyType<TSchema, Property>;
};
/**
 * Returns all array-specific element dot-notation properties of a schema with their corresponding types.
 *
 * https://www.mongodb.com/docs/v5.3/reference/operator/update/positional/#update-values-in-an-array
 * https://www.mongodb.com/docs/v5.3/reference/operator/update/positional-all/#update-all-elements-in-an-array
 * https://www.mongodb.com/docs/v5.3/reference/operator/update/positional-filtered/#update-all-array-elements-that-match-arrayfilters
 *
 * @example
 * {
 *   'numbersList.$': number;
 *   'numbersList.$[]': number;
 *   'numbersList.$[element]': number;
 * }
 */
export type PaprArrayElementsProperties<TSchema> = {
    [Property in `${KeysOfAType<PaprAllProperties<TSchema>, any[]>}.$${'' | `[${string}]`}`]?: ArrayElement<PropertyType<TSchema, Property extends `${infer Key}.$${string}` ? Key : never>>;
};
/**
 * Returns all array-specific nested dot-notation properties of a schema without type lookup.
 *
 * https://www.mongodb.com/docs/v5.3/reference/operator/update/positional/#update-documents-in-an-array
 * https://www.mongodb.com/docs/v5.3/reference/operator/update/positional-all/#update-all-documents-in-an-array
 * https://www.mongodb.com/docs/v5.3/reference/operator/update/positional-filtered/#update-all-documents-that-match-arrayfilters-in-an-array
 *
 * @example
 * {
 *   'objectList.$.foo': any;
 *   'objectList.$[].foo': any;
 *   'objectList.$[element].foo': any;
 * }
 */
export type PaprArrayNestedProperties<TSchema> = {
    [Property in `${KeysOfAType<PaprAllProperties<TSchema>, Record<string, any>[]>}.$${'' | `[${string}]`}.${string}`]?: any;
};
export type PaprMatchKeysAndValues<TSchema> = PaprAllProperties<TSchema> & PaprArrayElementsProperties<TSchema> & PaprArrayNestedProperties<TSchema>;
export interface PaprUpdateFilter<TSchema> {
    $currentDate?: OnlyFieldsOfType<TSchema, Date | Timestamp, true | {
        $type: 'date' | 'timestamp';
    }>;
    $inc?: OnlyFieldsOfType<TSchema, NumericType | undefined>;
    $min?: PaprMatchKeysAndValues<TSchema>;
    $max?: PaprMatchKeysAndValues<TSchema>;
    $mul?: OnlyFieldsOfType<TSchema, NumericType | undefined>;
    $rename?: Record<string, string>;
    $set?: PaprMatchKeysAndValues<TSchema>;
    $setOnInsert?: PaprMatchKeysAndValues<TSchema>;
    $unset?: OnlyFieldsOfType<TSchema, any, '' | 1 | true>;
    $addToSet?: SetFields<TSchema>;
    $pop?: OnlyFieldsOfType<TSchema, readonly any[], -1 | 1>;
    $pull?: PullOperator<TSchema>;
    $push?: PushOperator<TSchema>;
    $pullAll?: PullAllOperator<TSchema>;
    $bit?: OnlyFieldsOfType<TSchema, NumericType | undefined, {
        and: IntegerType;
    } | {
        or: IntegerType;
    } | {
        xor: IntegerType;
    }>;
}
