import type {
  CompiledFunctions,
  Dictionary,
  EntityData,
  EntityDictionary,
  EntityKey,
  EntityMetadata,
  EntityName,
  EntityProperty,
  Primary,
} from '../typings.js';
import type { Collection } from '../entity/Collection.js';
import type { Platform } from '../platforms/Platform.js';
import { type ScalarReference } from '../entity/Reference.js';
import { type RawQueryFragmentSymbol } from './RawQueryFragment.js';
/** Deeply compares two objects for equality, handling dates, regexes, and raw fragments. */
export declare function compareObjects(a: any, b: any): boolean;
/** Compares two arrays element-by-element for deep equality. */
export declare function compareArrays(a: any[] | string, b: any[] | string): boolean;
/** Compares two boolean values, treating numeric 0/1 as false/true. */
export declare function compareBooleans(a: unknown, b: unknown): boolean;
/** Compares two byte arrays element-by-element. */
export declare function compareBuffers(a: Uint8Array, b: Uint8Array): boolean;
/**
 * Checks if arguments are deeply (but not strictly) equal.
 */
export declare function equals(a: any, b: any): boolean;
/** Parses a JSON string safely, returning the original value if parsing fails. */
export declare function parseJsonSafe<T = unknown>(value: unknown): T;
/** Collection of general-purpose utility methods used throughout the ORM. */
export declare class Utils {
  #private;
  static readonly PK_SEPARATOR = '~~~';
  /**
   * Checks if the argument is instance of `Object`. Returns false for arrays.
   */
  static isObject<T = Dictionary>(o: any): o is T;
  /**
   * Removes `undefined` properties (recursively) so they are not saved as nulls
   */
  static dropUndefinedProperties(o: any, value?: null, visited?: Set<unknown>): void;
  /**
   * Returns the number of properties on `obj`. This is 20x faster than Object.keys(obj).length.
   * @see https://github.com/deepkit/deepkit-framework/blob/master/packages/core/src/core.ts
   */
  static getObjectKeysSize(object: Dictionary): number;
  /**
   * Returns true if `obj` has at least one property. This is 20x faster than Object.keys(obj).length.
   * @see https://github.com/deepkit/deepkit-framework/blob/master/packages/core/src/core.ts
   */
  static hasObjectKeys(object: Dictionary): boolean;
  /**
   * Checks if arguments are deeply (but not strictly) equal.
   */
  static equals(a: any, b: any): boolean;
  /**
   * Gets array without duplicates.
   */
  static unique<T = string>(items: T[]): T[];
  /**
   * Merges all sources into the target recursively.
   */
  static merge(target: any, ...sources: any[]): any;
  /**
   * Merges all sources into the target recursively. Ignores `undefined` values.
   */
  static mergeConfig<T>(target: T, ...sources: Dictionary[]): T;
  /**
   * Merges all sources into the target recursively.
   */
  private static _merge;
  /**
   * Creates deep copy of given object.
   */
  static copy<T>(entity: T, respectCustomCloneMethod?: boolean): T;
  /**
   * Normalize the argument to always be an array.
   */
  static asArray<T>(data?: T | readonly T[] | Iterable<T>, strict?: boolean): T[];
  /**
   * Checks if the value is iterable, but considers strings and buffers as not iterable.
   */
  static isIterable<T>(value: unknown): value is Iterable<T>;
  /**
   * Renames object key, keeps order of properties.
   */
  static renameKey<T>(payload: T, from: string | keyof T, to: string): void;
  /**
   * Returns array of functions argument names. Uses basic regex for source code analysis, might not work with advanced syntax.
   */
  static getConstructorParams(func: { toString(): string }): string[] | undefined;
  /**
   * Checks whether the argument looks like primary key (string, number or ObjectId).
   */
  static isPrimaryKey<T>(key: any, allowComposite?: boolean): key is Primary<T>;
  /**
   * Extracts primary key from `data`. Accepts objects or primary keys directly.
   */
  static extractPK<T extends object>(data: any, meta?: EntityMetadata<T>, strict?: boolean): Primary<T> | string | null;
  static getCompositeKeyValue<T>(
    data: EntityData<T>,
    meta: EntityMetadata<T>,
    convertCustomTypes?: boolean | 'convertToDatabaseValue' | 'convertToJSValue',
    platform?: Platform,
  ): Primary<T>;
  static getCompositeKeyHash<T>(
    data: EntityData<T>,
    meta: EntityMetadata<T>,
    convertCustomTypes?: boolean,
    platform?: Platform,
    flat?: boolean,
  ): string;
  static getPrimaryKeyHash(pks: (string | Buffer | Date)[]): string;
  static splitPrimaryKeys<T extends object>(key: string): EntityKey<T>[];
  static getPrimaryKeyValues<T>(
    entity: T,
    meta: EntityMetadata<T>,
    allowScalar?: boolean,
    convertCustomTypes?: boolean,
  ): any;
  static getPrimaryKeyCond<T>(entity: T, primaryKeys: EntityKey<T>[]): Record<string, Primary<T>> | null;
  /**
   * Maps nested FKs from `[1, 2, 3]` to `[1, [2, 3]]`.
   */
  static mapFlatCompositePrimaryKey(
    fk: Primary<any>[],
    prop: EntityProperty,
    fieldNames?: string[],
    idx?: number,
  ): Primary<any> | Primary<any>[];
  static getPrimaryKeyCondFromArray<T extends object>(
    pks: Primary<T>[],
    meta: EntityMetadata<T>,
  ): Record<string, Primary<T>>;
  static getOrderedPrimaryKeys<T>(
    id: Primary<T> | Record<string, Primary<T>>,
    meta: EntityMetadata<T>,
    platform?: Platform,
    convertCustomTypes?: boolean,
    allowScalar?: boolean,
  ): Primary<T>[];
  /**
   * Checks whether given object is an entity instance.
   */
  static isEntity<T = unknown>(data: any, allowReference?: boolean): data is T & {};
  /**
   * Checks whether given object is a scalar reference.
   */
  static isScalarReference<T = unknown>(data: any, allowReference?: boolean): data is ScalarReference<any> & {};
  /**
   * Checks whether the argument is empty (array without items, object without keys or falsy value).
   */
  static isEmpty(data: any): boolean;
  /**
   * Gets string name of given class.
   */
  static className<T>(classOrName: string | EntityName<T>): string;
  static extractChildElements(items: string[], prefix: string, allSymbol?: string): string[];
  /**
   * Tries to detect TypeScript support.
   */
  static detectTypeScriptSupport(): boolean;
  /**
   * Gets the type of the argument.
   */
  static getObjectType(value: any): string;
  /**
   * Checks whether the value is POJO (e.g. `{ foo: 'bar' }`, and not instance of `Foo`)
   */
  static isPlainObject<T extends Dictionary>(value: any): value is T;
  /**
   * Executes the `cb` promise serially on every element of the `items` array and returns array of resolved values.
   */
  static runSerial<T = any, U = any>(items: Iterable<U>, cb: (item: U) => Promise<T>): Promise<T[]>;
  static isCollection<T extends object, O extends object = object>(item: any): item is Collection<T, O>;
  static hash(data: string, length?: number): string;
  static runIfNotEmpty(clause: () => any, data: any): void;
  static defaultValue<T extends Dictionary>(prop: T, option: keyof T, defaultValue: any): void;
  static findDuplicates<T>(items: T[]): T[];
  static removeDuplicates<T>(items: T[]): T[];
  static randomInt(min: number, max: number): number;
  /**
   * Extracts all possible values of a TS enum. Works with both string and numeric enums.
   */
  static extractEnumValues(target: Dictionary): (string | number)[];
  static flatten<T>(arrays: T[][], deep?: boolean): T[];
  static isOperator(key: PropertyKey, includeGroupOperators?: boolean): boolean;
  static hasNestedKey(object: unknown, key: string): boolean;
  static getORMVersion(): string;
  static createFunction(
    context: Map<string, any>,
    code: string,
    compiledFunctions?: CompiledFunctions,
    key?: string,
  ): any;
  static callCompiledFunction<T extends unknown[], R>(fn: (...args: T) => R, ...args: T): R;
  static unwrapProperty<T>(
    entity: T,
    meta: EntityMetadata<T>,
    prop: EntityProperty<T>,
    payload?: boolean,
  ): [unknown, number[]][];
  static setPayloadProperty<T>(
    entity: EntityDictionary<T>,
    meta: EntityMetadata<T>,
    prop: EntityProperty<T>,
    value: unknown,
    idx: number[],
  ): void;
  static tryImport<T extends Dictionary = any>({
    module,
    warning,
  }: {
    module: string;
    warning?: string;
  }): Promise<T | undefined>;
  static xor(a: boolean, b: boolean): boolean;
  static keys<T extends object>(obj: T): (keyof T)[];
  static values<T extends object>(obj: T): T[keyof T][];
  static entries<T extends object>(obj: T): [keyof T, T[keyof T]][];
  static primaryKeyToObject<T>(meta: EntityMetadata<T>, primaryKey: Primary<T> | T, visible?: (keyof T)[]): T;
  static getObjectQueryKeys<T extends Dictionary, K extends string = Extract<keyof T, string>>(
    obj: T,
  ): (K | RawQueryFragmentSymbol)[];
}
