import type { PopulatePath } from '../enums.js';
import type { EntityManager } from '../EntityManager.js';
import type {
  Dictionary,
  EntityData,
  EntityDictionary,
  EntityMetadata,
  IHydrator,
  EntityKey,
  PopulateOptions,
  Primary,
  AutoPath,
  Ref,
  AddEager,
  LoadedReference,
  EntityDTO,
  Loaded,
  SerializeDTO,
  FromEntityType,
  IsSubset,
  MergeSelected,
} from '../typings.js';
import { Reference } from './Reference.js';
import { type AssignOptions } from './EntityAssigner.js';
import type { EntityLoaderOptions } from './EntityLoader.js';
import type { EntityIdentifier } from './EntityIdentifier.js';
import type { SerializationContext } from '../serialization/SerializationContext.js';
import { type SerializeOptions } from '../serialization/EntitySerializer.js';
import type { FindOneOptions, LoadHint } from '../drivers/IDatabaseDriver.js';
import type { Platform } from '../platforms/Platform.js';
import type { Configuration } from '../utils/Configuration.js';
/** @internal Wrapper attached to every managed entity, holding ORM state such as initialization flags, identity map references, and change tracking snapshots. */
export declare class WrappedEntity<Entity extends object> {
  __initialized: boolean;
  __populated?: boolean;
  __managed?: boolean;
  __onLoadFired?: boolean;
  __schema?: string;
  __em?: EntityManager;
  __loadedProperties: Set<string>;
  __data: Dictionary;
  __processing: boolean;
  __serializationContext: {
    root?: SerializationContext<Entity>;
    populate?: PopulateOptions<Entity>[];
    fields?: Set<string>;
    exclude?: readonly string[];
  };
  /** stores last known primary key, as its current state might be broken due to propagation/orphan removal, but we need to know the PK to be able t remove the entity */
  __pk?: Primary<Entity>;
  /** holds the reference wrapper instance (if created), so we can maintain the identity on reference wrappers too */
  __reference?: Reference<Entity>;
  /** holds last entity data snapshot, so we can compute changes when persisting managed entities */
  __originalEntityData?: EntityData<Entity>;
  /** holds wrapped primary key, so we can compute change set without eager commit */
  __identifier?: EntityIdentifier;
  private readonly entity;
  private readonly hydrator;
  private readonly pkGetter?;
  private readonly pkSerializer?;
  private readonly pkGetterConverted?;
  constructor(
    entity: Entity,
    hydrator: IHydrator,
    pkGetter?: (e: Entity) => Primary<Entity>,
    pkSerializer?: (e: Entity) => string,
    pkGetterConverted?: (e: Entity) => Primary<Entity>,
  );
  /** Returns whether the entity has been fully loaded from the database. */
  isInitialized(): boolean;
  /** Returns whether the entity is managed by an EntityManager (tracked in the identity map). */
  isManaged(): boolean;
  /** Marks the entity as populated or not for serialization purposes. */
  populated(populated?: boolean | undefined): void;
  /** Sets the serialization context with populate hints, field selections, and exclusions. */
  setSerializationContext<Hint extends string = never, Fields extends string = '*', Exclude extends string = never>(
    options: LoadHint<Entity, Hint, Fields, Exclude>,
  ): void;
  /** Returns a Reference wrapper for this entity, creating one if it does not already exist. */
  toReference(): Ref<Entity> & LoadedReference<Loaded<Entity, AddEager<Entity>>>;
  /** Converts the entity to a plain object representation, optionally excluding specified fields. */
  toObject<Ignored extends EntityKey<Entity> = never>(ignoreFields?: Ignored[]): Omit<EntityDTO<Entity>, Ignored>;
  /** Serializes the entity with control over which relations and fields to include or exclude. */
  serialize<Hint extends string = never, Exclude extends string = never>(
    options?: SerializeOptions<Entity, Hint, Exclude>,
  ): SerializeDTO<Entity, Hint, Exclude>;
  /** Converts the entity to a plain object, including all properties regardless of serialization rules. */
  toPOJO(): EntityDTO<Entity>;
  /** Serializes the entity using its `toJSON` method (supports `JSON.stringify`). */
  toJSON(...args: any[]): EntityDictionary<Entity>;
  /** Assigns the given data to this entity, updating its properties and relations. */
  assign<
    Naked extends FromEntityType<Entity> = FromEntityType<Entity>,
    Convert extends boolean = false,
    Data extends EntityData<Naked, Convert> | Partial<EntityDTO<Naked>> =
      | EntityData<Naked, Convert>
      | Partial<EntityDTO<Naked>>,
  >(
    data: Data & IsSubset<EntityData<Naked>, Data>,
    options?: AssignOptions<Convert>,
  ): MergeSelected<Entity, Naked, keyof Data & string>;
  /** Initializes (refreshes) the entity by reloading it from the database. Returns null if not found. */
  init<Hint extends string = never, Fields extends string = '*', Excludes extends string = never>(
    options?: FindOneOptions<Entity, Hint, Fields, Excludes>,
  ): Promise<Loaded<Entity, Hint, Fields, Excludes> | null>;
  /** Loads the specified relations on this entity. */
  populate<Hint extends string = never, Fields extends string = never>(
    populate: AutoPath<Entity, Hint, PopulatePath.ALL>[] | false,
    options?: EntityLoaderOptions<Entity, Fields>,
  ): Promise<Loaded<Entity, Hint>>;
  /** Returns whether this entity has a primary key value set. */
  hasPrimaryKey(): boolean;
  /** Returns the primary key value, optionally converting custom types to their database representation. */
  getPrimaryKey(convertCustomTypes?: boolean): Primary<Entity> | null;
  /** Returns all primary key values as an array. Used internally for composite key handling. */
  getPrimaryKeys(convertCustomTypes?: boolean): Primary<Entity>[] | null;
  /** Returns the database schema this entity belongs to. */
  getSchema(): string | undefined;
  /** Sets the database schema for this entity. */
  setSchema(schema?: string): void;
  /** Sets the primary key value on the entity. */
  setPrimaryKey(id: Primary<Entity> | null): void;
  /** Returns the primary key serialized as a string suitable for identity map lookups. */
  getSerializedPrimaryKey(): string;
  get __meta(): EntityMetadata<Entity>;
  get __platform(): Platform;
  get __config(): Configuration;
  get __primaryKeys(): Primary<Entity>[];
}
