export type FieldType = 'string' | 'text' | 'number' | 'boolean' | 'date' | 'json' | 'array';
export interface FieldDef {
    type: FieldType;
    required?: boolean;
    unique?: boolean;
    sparse?: boolean;
    default?: unknown;
    enum?: string[];
    lowercase?: boolean;
    trim?: boolean;
    arrayOf?: FieldType | EmbeddedSchemaDef;
}
/** Embedded sub-document (e.g. Activity.schedule[], SubscriptionPlan.activities[]) */
export interface EmbeddedSchemaDef {
    kind: 'embedded';
    fields: Record<string, FieldDef>;
}
export type RelationType = 'one-to-one' | 'many-to-one' | 'one-to-many' | 'many-to-many';
export interface RelationDef {
    /** Target entity name (e.g. 'User', 'Client') */
    target: string;
    type: RelationType;
    required?: boolean;
    /** Default fields to select when populating/joining */
    select?: string[];
    /** Whether this relation can be null */
    nullable?: boolean;
    /** Junction table name (SQL dialects) — convention: "{source}_{target}" in snake_case */
    through?: string;
}
export type IndexType = 'asc' | 'desc' | 'text';
export interface IndexDef {
    fields: Record<string, IndexType>;
    unique?: boolean;
    sparse?: boolean;
}
export interface EntitySchema {
    /** Entity name (PascalCase, e.g. 'Client') */
    name: string;
    /** Collection/table name (e.g. 'clients') */
    collection: string;
    /** Field definitions */
    fields: Record<string, FieldDef>;
    /** Relations to other entities */
    relations: Record<string, RelationDef>;
    /** Database indexes */
    indexes: IndexDef[];
    /** Auto-manage createdAt/updatedAt */
    timestamps: boolean;
    /** Discriminator field name (e.g. '_type'). If set, enables single-table mode. */
    discriminator?: string;
    /** Discriminator value for this entity (e.g. 'article'). Used to filter rows in a shared table. */
    discriminatorValue?: string;
    /** Enable soft delete (adds deletedAt field, auto-filters on find) */
    softDelete?: boolean;
}
export interface FilterOperator {
    $eq?: unknown;
    $ne?: unknown;
    $gt?: unknown;
    $gte?: unknown;
    $lt?: unknown;
    $lte?: unknown;
    $in?: unknown[];
    $nin?: unknown[];
    $regex?: string;
    $regexFlags?: string;
    $exists?: boolean;
}
export type FilterValue = unknown | FilterOperator;
export interface FilterQuery {
    [field: string]: FilterValue;
    $or?: FilterQuery[];
    $and?: FilterQuery[];
}
export type SortDirection = 1 | -1;
export interface QueryOptions {
    sort?: Record<string, SortDirection>;
    skip?: number;
    limit?: number;
    /** Fields to include in result (projection) */
    select?: string[];
    /** Fields to exclude from result */
    exclude?: string[];
}
export interface PaginatedResult<T> {
    data: T[];
    total: number;
    page: number;
    limit: number;
    totalPages: number;
}
export interface AggregateGroupStage {
    $group: {
        _by: string | null;
        [field: string]: AggregateAccumulator | string | null;
    };
}
export interface AggregateAccumulator {
    $sum?: number | string;
    $count?: true;
    $avg?: string;
    $min?: string;
    $max?: string;
}
export interface AggregateMatchStage {
    $match: FilterQuery;
}
export interface AggregateSortStage {
    $sort: Record<string, SortDirection>;
}
export interface AggregateLimitStage {
    $limit: number;
}
export type AggregateStage = AggregateMatchStage | AggregateGroupStage | AggregateSortStage | AggregateLimitStage;
export type DialectType = 'mongodb' | 'sqlite' | 'postgres' | 'mysql' | 'mariadb' | 'oracle' | 'mssql' | 'cockroachdb' | 'db2' | 'hana' | 'hsqldb' | 'spanner' | 'sybase';
/**
 * Schema generation strategy (inspired by hibernate.hbm2ddl.auto)
 *
 *   validate     : validate schema, make no changes (production)
 *   update       : update schema to match entities (dev)
 *   create       : drop and recreate schema on startup
 *   create-drop  : drop schema on shutdown
 *   none         : do nothing
 */
export type SchemaStrategy = 'validate' | 'update' | 'create' | 'create-drop' | 'none';
/**
 * Connection configuration — inspired by Hibernate persistence.xml
 *
 * Equivalent persistence.xml properties :
 *   jakarta.persistence.jdbc.url     → uri
 *   hibernate.dialect                → dialect
 *   hibernate.show_sql               → showSql
 *   hibernate.format_sql             → formatSql
 *   hibernate.highlight_sql          → highlightSql
 *   hibernate.hbm2ddl.auto           → schemaStrategy
 *   hibernate.connection.pool_size   → poolSize
 *   hibernate.cache.use_second_level → cacheEnabled
 *   hibernate.default_batch_fetch_size → batchSize
 */
export interface ConnectionConfig {
    dialect: DialectType;
    uri: string;
    /** Log generated queries to console (default: false) */
    showSql?: boolean;
    /** Pretty-print logged queries (default: false) */
    formatSql?: boolean;
    /** Colorize SQL keywords in terminal output (default: false) */
    highlightSql?: boolean;
    /** Schema generation strategy (default: 'none') */
    schemaStrategy?: SchemaStrategy;
    /** Max connections in pool (default: dialect-specific) */
    poolSize?: number;
    /** Enable query result caching (default: false) */
    cacheEnabled?: boolean;
    /** Cache TTL in seconds (default: 60) */
    cacheTtlSeconds?: number;
    /** Default batch size for bulk operations (default: 25) */
    batchSize?: number;
    /** Additional dialect-specific options */
    options?: Record<string, unknown>;
}
export interface IDialect {
    readonly dialectType: DialectType;
    connect(config: ConnectionConfig): Promise<void>;
    disconnect(): Promise<void>;
    testConnection(): Promise<boolean>;
    initSchema(schemas: EntitySchema[]): Promise<void>;
    find<T = Record<string, unknown>>(schema: EntitySchema, filter: FilterQuery, options?: QueryOptions): Promise<T[]>;
    findOne<T = Record<string, unknown>>(schema: EntitySchema, filter: FilterQuery, options?: QueryOptions): Promise<T | null>;
    findById<T = Record<string, unknown>>(schema: EntitySchema, id: string, options?: QueryOptions): Promise<T | null>;
    create<T = Record<string, unknown>>(schema: EntitySchema, data: Record<string, unknown>): Promise<T>;
    update<T = Record<string, unknown>>(schema: EntitySchema, id: string, data: Record<string, unknown>): Promise<T | null>;
    updateMany(schema: EntitySchema, filter: FilterQuery, data: Record<string, unknown>): Promise<number>;
    delete(schema: EntitySchema, id: string): Promise<boolean>;
    deleteMany(schema: EntitySchema, filter: FilterQuery): Promise<number>;
    count(schema: EntitySchema, filter: FilterQuery): Promise<number>;
    distinct(schema: EntitySchema, field: string, filter: FilterQuery): Promise<unknown[]>;
    aggregate<T = Record<string, unknown>>(schema: EntitySchema, stages: AggregateStage[]): Promise<T[]>;
    findWithRelations<T = Record<string, unknown>>(schema: EntitySchema, filter: FilterQuery, relations: string[], options?: QueryOptions): Promise<T[]>;
    findByIdWithRelations<T = Record<string, unknown>>(schema: EntitySchema, id: string, relations: string[], options?: QueryOptions): Promise<T | null>;
    upsert<T = Record<string, unknown>>(schema: EntitySchema, filter: FilterQuery, data: Record<string, unknown>): Promise<T>;
    increment(schema: EntitySchema, id: string, field: string, amount: number): Promise<Record<string, unknown>>;
    addToSet(schema: EntitySchema, id: string, field: string, value: unknown): Promise<Record<string, unknown> | null>;
    pull(schema: EntitySchema, id: string, field: string, value: unknown): Promise<Record<string, unknown> | null>;
    search<T = Record<string, unknown>>(schema: EntitySchema, query: string, fields: string[], options?: QueryOptions): Promise<T[]>;
    /** Drop a single table by name */
    dropTable?(tableName: string): Promise<void>;
    /** Drop all tables in the database (dangerous) */
    dropAllTables?(): Promise<void>;
    /** Drop tables for registered schemas + their junction tables */
    dropSchema?(schemas: EntitySchema[]): Promise<string[]>;
    /** Truncate (empty) a single table — keeps structure, deletes data */
    truncateTable?(tableName: string): Promise<void>;
    /** Truncate all registered schema tables — keeps structure, deletes data */
    truncateAll?(schemas: EntitySchema[]): Promise<string[]>;
}
export interface IRepository<T> {
    findAll(filter?: FilterQuery, options?: QueryOptions): Promise<T[]>;
    findOne(filter: FilterQuery, options?: QueryOptions): Promise<T | null>;
    findById(id: string, options?: QueryOptions): Promise<T | null>;
    findByIdWithRelations(id: string, relations?: string[], options?: QueryOptions): Promise<T | null>;
    create(data: Partial<T>): Promise<T>;
    update(id: string, data: Partial<T>): Promise<T | null>;
    updateMany(filter: FilterQuery, data: Partial<T>): Promise<number>;
    delete(id: string): Promise<boolean>;
    deleteMany(filter: FilterQuery): Promise<number>;
    count(filter?: FilterQuery): Promise<number>;
    search(query: string, options?: QueryOptions): Promise<T[]>;
    distinct(field: string, filter?: FilterQuery): Promise<unknown[]>;
    aggregate<R = Record<string, unknown>>(stages: AggregateStage[]): Promise<R[]>;
    upsert(filter: FilterQuery, data: Partial<T>): Promise<T>;
    increment(id: string, field: string, amount: number): Promise<T | null>;
    addToSet(id: string, field: string, value: unknown): Promise<T | null>;
    pull(id: string, field: string, value: unknown): Promise<T | null>;
    findWithRelations(filter: FilterQuery, relations: string[], options?: QueryOptions): Promise<T[]>;
}
export interface HookContext {
    entity: EntitySchema;
    dialect: DialectType;
    operation: 'create' | 'update' | 'delete' | 'find';
    userId?: string;
}
export interface IPlugin {
    name: string;
    /** Modify the schema at boot time (add fields, indexes...) */
    onSchemaInit?(schema: EntitySchema): EntitySchema;
    /** Before insert */
    preSave?(doc: Record<string, unknown>, ctx: HookContext): Promise<Record<string, unknown>> | Record<string, unknown>;
    /** After insert */
    postSave?(doc: Record<string, unknown>, ctx: HookContext): Promise<void> | void;
    /** Before update */
    preUpdate?(id: string, data: Record<string, unknown>, ctx: HookContext): Promise<Record<string, unknown>> | Record<string, unknown>;
    /** After update */
    postUpdate?(doc: Record<string, unknown>, ctx: HookContext): Promise<void> | void;
    /** Before delete */
    preDelete?(id: string, ctx: HookContext): Promise<void> | void;
    /** Transform queries (e.g. soft-delete auto-filter) */
    onQuery?(filter: FilterQuery, ctx: HookContext): FilterQuery;
    /** Transform results (e.g. normalization) */
    onResult?(doc: Record<string, unknown>, ctx: HookContext): Record<string, unknown>;
}
/** Normalized document: id (string) instead of _id */
export interface NormalizedDoc {
    id: string;
    [key: string]: unknown;
}
