import type { SchemaDefinition, IndexDefinition, AssociationDefinition } from '@baasix/types';
import type { PluginSchemaDefinition } from '../types/plugin.js';
/**
 * Internal association with additional properties used during schema processing.
 */
interface InternalAssociation extends Omit<AssociationDefinition, 'target'> {
    model: string;
    target?: string;
    otherKey?: string;
    polymorphic?: boolean;
}
/**
 * Extended schema definition for internal runtime use.
 * Adds optional properties that may be created/mutated during schema processing.
 */
interface InternalSchemaDefinition extends SchemaDefinition {
    /** Runtime-added options for multi-tenant index handling */
    options?: {
        paranoid?: boolean;
        timestamps?: boolean;
        indexes?: IndexDefinition[];
    };
    /** Runtime-extracted associations from fields */
    associations?: Record<string, InternalAssociation>;
}
declare global {
    var __baasix_schemaManager: SchemaManager | undefined;
}
/**
 * Manages dynamic schema generation from JSON definitions
 */
export declare class SchemaManager {
    private static instance;
    private schemas;
    private schemaDefinitions;
    private relations;
    private initialized;
    private pluginSchemas;
    private constructor();
    /**
     * Register plugin schemas before initialization
     * This should be called before initialize() to ensure plugin schemas are created with system schemas
     */
    registerPluginSchemas(schemas: PluginSchemaDefinition[]): void;
    /**
     * Get all registered plugin schemas
     */
    getPluginSchemas(): PluginSchemaDefinition[];
    /**
     * Get singleton instance
     */
    static getInstance(): SchemaManager;
    /**
     * Initialize schema manager by loading all schemas from database
     * Flow matches Sequelize implementation:
     * 1. Ensure SchemaDefinition table exists
     * 2. Ensure system schemas are in SchemaDefinition table
     * 3. Create tables for schemas that need syncing
     * 4. Load all schemas
     * 5. Seed database if empty
     */
    initialize(): Promise<void>;
    /**
     * Enable required PostgreSQL extensions
     */
    private enablePostgresExtensions;
    /**
     * Ensure baasix_SchemaDefinition table exists
     */
    private ensureSchemaDefinitionTable;
    /**
     * Ensure system schemas and plugin schemas are in the baasix_SchemaDefinition table
     * Returns list of schemas that need syncing
     */
    private ensureSystemSchemas;
    /**
     * Sort schemas by dependency order (topological sort)
     */
    private sortSchemasByDependencies;
    /**
     * Load and create tables for specific schemas
     */
    private loadAndCreateAllSchemas;
    /**
     * Normalize legacy Sequelize schemas - add default values for timestamp fields
     * and update DB column defaults if missing
     */
    private normalizeLegacySchema;
    /**
     * Load all schemas from database into memory
     * @param schemasNeedingSync - List of schema names that need table sync (from ensureSystemSchemas)
     *                             If empty, skip expensive sync operations for faster startup
     */
    private loadAllSchemas;
    /**
     * Sync table columns with schema definition (add missing columns)
     */
    private syncTableColumns;
    /**
     * Create table from schema definition using raw SQL
     */
    private createTableFromSchema;
    /**
     * Ensure foreign key constraints exist for BelongsTo relations
     */
    private ensureForeignKeyConstraints;
    /**
     * Create an index on a table
     */
    /**
     * Auto-create an HNSW index for a pgvector column.
     * Uses cosine distance (vector_cosine_ops) by default — best for normalized embeddings.
     * halfvec and sparsevec use their respective operator classes.
     */
    private createVectorIndex;
    private createIndex;
    /**
     * Build column definition for CREATE TABLE
     */
    private buildColumnDefinition;
    /**
     * Convert a schema field's defaultValue into a raw SQL DEFAULT expression (without the "DEFAULT" keyword).
     * Returns null if no default is defined.
     */
    private getDefaultExpression;
    /**
     * Normalize a default expression for comparison.
     * PostgreSQL stores defaults with type casts (e.g. 'hello'::text, now(), gen_random_uuid())
     * so we strip casts and lowercase for a fair comparison.
     */
    private normalizeDefaultForComparison;
    /**
     * Check if database is empty and seed if needed
     */
    private checkAndSeedDatabase;
    /**
     * Seed the database with initial data
     */
    private seedDatabase;
    /**
     * Seed default email templates into baasix_Template table
     */
    private seedDefaultTemplates;
    /**
     * Ensure baasix_SchemaDefinition table exists
     */
    private ensureSchemaDefinitionTableOLD;
    /**
     * Create or update a model from JSON schema definition
     */
    createOrUpdateModel(collectionName: string, jsonSchema: InternalSchemaDefinition): Promise<any>;
    /**
     * Create indexes for a table
     */
    private createIndexes;
    /**
     * Register model-specific hooks
     */
    private registerModelHooks;
    /**
     * Get a registered schema by collection name
     */
    getSchema(collectionName: string): any;
    /**
     * Get all registered schemas
     */
    getAllSchemas(): Map<string, any>;
    /**
     * Check if a model/collection exists
     */
    modelExists(collectionName: string): boolean;
    /**
     * Get table for a collection
     */
    getTable(collectionName: string): any;
    /**
     * Get primary key field name for a collection
     */
    getPrimaryKey(collectionName: string): string;
    /**
     * Get the names of fields marked `hidden` in the JSON schema definition.
     *
     * IMPORTANT: the `hidden` flag lives on the schema DEFINITION (schemaDefinitions
     * map), NOT on the runtime Drizzle table (`getSchema().columns`). Reading it from
     * the Drizzle table returns nothing, which previously let hidden fields like
     * `password` leak into API responses. Always source hidden fields from here.
     */
    getHiddenFieldNames(collectionName: string): string[];
    /**
     * Check if a collection has paranoid mode enabled (soft delete)
     */
    isParanoid(collectionName: string): boolean;
    /**
     * Get schema options for a collection
     */
    getSchemaOptions(collectionName: string): any;
    /**
     * Get schema definition with flags from baasix_SchemaDefinition table
     */
    getSchemaDefinition(collectionName: string): Promise<any | null>;
    /**
     * Get relation names for a collection
     */
    getRelationNames(collectionName: string): string[];
    /**
     * Get relations for a collection
     */
    getRelations(collectionName: string): any;
    /**
     * Get a specific relation for a collection
     */
    getRelation(collectionName: string, relationName: string): any;
    /**
     * Check if schema manager is initialized
     */
    isInitialized(): boolean;
    /**
     * Add a new schema definition to the database
     */
    addSchemaDefinition(collectionName: string, schema: SchemaDefinition): Promise<void>;
    /**
     * Remove a schema definition
     */
    removeSchemaDefinition(collectionName: string): Promise<void>;
    /**
     * Sync schemas - create/update tables in database
     * Similar to Sequelize.sync()
     */
    sync(options?: {
        force?: boolean;
        alter?: boolean;
    }): Promise<void>;
    /**
     * Create or update a model (for schema routes compatibility)
     */
    updateModel(collectionName: string, schema: any, accountability?: any): Promise<void>;
    /**
     * Delete a model (for schema routes compatibility)
     */
    deleteModel(collectionName: string): Promise<void>;
    /**
     * Add an index to a collection
     */
    addIndex(collectionName: string, indexData: any, accountability?: any): Promise<void>;
    /**
     * Remove an index (stub for compatibility)
     */
    removeIndex(collectionName: string, indexName: string, accountability?: any): Promise<void>;
    /**
     * Add missing foreign key indexes to all collections
     * Useful for migrating existing databases to use auto-indexing
     */
    addMissingForeignKeyIndexes(accountability?: any): Promise<{
        created: Array<{
            collection: string;
            indexName: string;
            field: string;
        }>;
        skipped: Array<{
            collection: string;
            indexName: string;
            reason: string;
        }>;
        errors: Array<{
            collection: string;
            indexName: string;
            error: string;
        }>;
    }>;
}
/**
 * Export singleton instance
 */
export declare const schemaManager: SchemaManager;
/**
 * Initialize schema manager
 */
export declare function initializeSchemas(): Promise<void>;
/**
 * Get schema by collection name
 */
export declare function getSchema(collectionName: string): any;
/**
 * Get all schemas
 */
export declare function getAllSchemas(): Map<string, any>;
export {};
//# sourceMappingURL=schemaManager.d.ts.map