import type { StandardSchemaV1 } from "@standard-schema/spec";
/**
 * Any Standard Schema compatible validator.
 */
export type StandardSchema = StandardSchemaV1<unknown, unknown>;
/**
 * Infer the parsed output type from a Standard Schema.
 */
export type InferOutput<T extends StandardSchemaV1> = StandardSchemaV1.InferOutput<T>;
type AnyMethods = Record<string, any>;
/**
 * Base entity instance passed to the `.methods(...)` builder: validated props
 * plus the `with` and `toJSON` helpers, before domain methods attach.
 *
 * `with(...)` is typed as returning the base instance here because the final
 * methods object is still being defined while the builder runs. At runtime
 * the returned instance carries the entity's methods, and `EntityInstance`
 * maps base-instance returns back to the full instance type so consumers keep
 * typed method chaining.
 */
export type EntityBaseInstance<Schema extends StandardSchema> = InferOutput<Schema> & {
    /**
     * Create a new validated entity instance with patched properties.
     */
    with(patch: Partial<InferOutput<Schema>>): EntityBaseInstance<Schema> | Promise<EntityBaseInstance<Schema>>;
    /**
     * Convert the entity to a plain JSON object for persistence.
     */
    toJSON(): InferOutput<Schema>;
};
/**
 * Replace base-instance returns with the full entity instance type, unwrapping
 * promises, so methods that return `self` or `self.with(...)` chain with the
 * entity's methods attached.
 */
type WithEntityInstance<R, Instance, Schema extends StandardSchema> = R extends Promise<infer P> ? Promise<WithEntityInstance<P, Instance, Schema>> : R extends EntityBaseInstance<Schema> ? Instance : R;
/**
 * Entity instance with validated props, attached methods, and immutable update
 * helpers. Method returns that are typed as the base instance (`self` or
 * `self.with(...)`) are mapped to the full instance type so chaining keeps
 * the entity's methods.
 */
export type EntityInstance<Name extends string, Schema extends StandardSchema, Methods extends AnyMethods> = InferOutput<Schema> & {
    /**
     * Create a new validated entity instance with patched properties.
     */
    with(patch: Partial<InferOutput<Schema>>): EntityInstance<Name, Schema, Methods> | Promise<EntityInstance<Name, Schema, Methods>>;
    /**
     * Convert the entity to a plain JSON object for persistence.
     */
    toJSON(): InferOutput<Schema>;
} & {
    [K in keyof Methods]: Methods[K] extends (...args: infer A) => infer R ? (...args: A) => WithEntityInstance<R, EntityInstance<Name, Schema, Methods>, Schema> : Methods[K];
};
/**
 * Entity definition returned by `defineEntity(...).build()`.
 */
export interface EntityDef<Name extends string, Schema extends StandardSchema, Methods extends AnyMethods> {
    /** Name used for debugging and introspection. */
    name: Name;
    /** Standard Schema used to validate entity props. */
    schema: Schema;
    /**
     * Create a new frozen entity instance from props.
     *
     * Returns a promise when the underlying Standard Schema validates async.
     */
    create(props: InferOutput<Schema>): EntityInstance<Name, Schema, Methods> | Promise<EntityInstance<Name, Schema, Methods>>;
    /**
     * Reconstruct an entity instance from JSON, usually from persistence.
     */
    fromJSON(json: InferOutput<Schema>): EntityInstance<Name, Schema, Methods> | Promise<EntityInstance<Name, Schema, Methods>>;
    /** Type-only alias for the entity instance type. Undefined at runtime. */
    Type: EntityInstance<Name, Schema, Methods>;
}
/**
 * Builder class for creating Entities/Aggregates.
 */
declare class EntityBuilder<Name extends string, Schema extends StandardSchema, Methods extends AnyMethods> {
    private readonly cfg;
    constructor(cfg: {
        name: Name;
        schema?: Schema;
        methods?: (self: EntityBaseInstance<Schema>) => Methods;
    });
    /**
     * Define the schema for this entity using any Standard Schema compatible validator.
     */
    props<S extends StandardSchema>(schema: S): EntityBuilder<Name, S, Methods>;
    /**
     * Define methods to attach to entity instances.
     * The method builder receives the typed base instance: validated props plus
     * `with` and `toJSON`.
     */
    methods<M extends AnyMethods>(build: (self: EntityBaseInstance<Schema>) => M): EntityBuilder<Name, Schema, M>;
    /**
     * Finalize and build the entity definition.
     */
    build(): EntityDef<Name, Schema, Methods>;
}
/**
 * Create a new entity builder.
 *
 * Entities validate props, attach domain methods, and return frozen immutable
 * instances. `with(...)` revalidates the merged props. `.Type` is type-only and
 * should be used with `typeof Entity.Type`.
 *
 * @example
 * ```ts
 * const Todo = defineEntity("Todo")
 *   .props(z.object({
 *     id: z.string(),
 *     title: z.string(),
 *     assigneeIds: z.array(z.string()).default([]),
 *   }))
 *   .methods((self) => ({
 *     addAssignee(id: string) {
 *       if (self.assigneeIds.includes(id)) return self;
 *       return self.with({ assigneeIds: [...self.assigneeIds, id] });
 *     },
 *   }))
 *   .build();
 *
 * type Todo = typeof Todo.Type;
 * ```
 */
export declare function defineEntity<Name extends string>(name: Name): EntityBuilder<Name, StandardSchema, Record<string, never>>;
export {};
//# sourceMappingURL=entity.d.ts.map