import { StandardSchemaV1 } from '@standard-schema/spec';
import { Column } from './column.js';
import { ContainerDbType, FieldBuilder, FieldBuilder as FieldBuilderType } from './field-builders.js';
/**
 * Extract the output type from a FieldBuilder.
 * This is what you get when reading from the database.
 *
 * This type extracts the TOutput type parameter, which is set by readValidator()
 * and represents the transformed/validated output type.
 */
export type InferFieldOutput<F> = F extends FieldBuilder<infer TOutput, any, any, any> ? TOutput : never;
/**
 * Extract the input type from a FieldBuilder.
 * This is what you pass when writing to the database.
 *
 * This type extracts the TInput type parameter, which is set by writeValidator()
 * and represents the transformed/validated input type.
 */
type InferFieldInput<F> = F extends FieldBuilder<any, infer TInput, any, any> ? TInput : never;
/**
 * Build a schema type from field builders (output/read types).
 */
type InferSchemaFromFields<TFields extends Record<string, FieldBuilder<any, any, any, any>>> = {
    [K in keyof TFields]: InferFieldOutput<TFields[K]>;
};
/**
 * Build an input schema type from field builders (input/write types).
 * Used for insert and update operations.
 */
type InferInputSchemaFromFields<TFields extends Record<string, FieldBuilder<any, any, any, any>>> = {
    [K in keyof TFields]: InferFieldInput<TFields[K]>;
};
/**
 * Check if a field is a container field by inspecting its TDbType.
 * Container fields have a branded TDbType that extends ContainerDbType.
 */
type IsContainerField<F> = F extends FieldBuilder<any, any, infer TDbType, any> ? NonNullable<TDbType> extends ContainerDbType ? true : false : false;
/**
 * Extract only selectable (non-container) field keys from a fields record.
 * Container fields are excluded because they cannot be selected via $select in FileMaker OData.
 */
type SelectableFieldKeys<TFields extends Record<string, FieldBuilder<any, any, any, any>>> = {
    [K in keyof TFields]: IsContainerField<TFields[K]> extends true ? never : K;
}[keyof TFields];
/**
 * Internal Symbols for table properties (hidden from IDE autocomplete).
 * These are used to store internal configuration that shouldn't be visible
 * when users access table columns.
 * @internal - Not exported from public API, only accessible via FMTable.Symbol
 */
declare const FMTableName: unique symbol;
declare const FMTableEntityId: unique symbol;
declare const FMTableSchema: unique symbol;
declare const FMTableFields: unique symbol;
declare const FMTableNavigationPaths: unique symbol;
declare const FMTableDefaultSelect: unique symbol;
declare const FMTableBaseTableConfig: unique symbol;
declare const FMTableUseEntityIds: unique symbol;
declare const FMTableComment: unique symbol;
/**
 * Base table class with Symbol-based internal properties.
 * This follows the Drizzle ORM pattern where internal configuration
 * is stored via Symbols, keeping it hidden from IDE autocomplete.
 */
export declare class FMTable<TFields extends Record<string, FieldBuilder<any, any, any, any>> = any, TName extends string = string, TNavigationPaths extends readonly string[] = readonly string[]> {
    /**
     * Internal Symbols for accessing table metadata.
     * @internal - Not intended for public use. Access table properties via columns instead.
     */
    static readonly Symbol: {
        Name: symbol;
        EntityId: symbol;
        UseEntityIds: symbol;
        Schema: symbol;
        Fields: symbol;
        NavigationPaths: symbol;
        DefaultSelect: symbol;
        BaseTableConfig: symbol;
        Comment: symbol;
    };
    /** @internal */
    [FMTableName]: TName;
    /** @internal */
    [FMTableEntityId]?: `FMTID:${string}`;
    /** @internal */
    [FMTableUseEntityIds]?: boolean;
    /** @internal */
    [FMTableComment]?: string;
    /** @internal */
    [FMTableSchema]: Partial<Record<keyof TFields, StandardSchemaV1>>;
    /** @internal */
    [FMTableFields]: TFields;
    /** @internal */
    [FMTableNavigationPaths]: TNavigationPaths;
    /** @internal */
    [FMTableDefaultSelect]: "all" | "schema" | Record<string, Column<any, any, TName>>;
    /** @internal */
    [FMTableBaseTableConfig]: {
        schema: Partial<Record<keyof TFields, StandardSchemaV1>>;
        inputSchema?: Partial<Record<keyof TFields, StandardSchemaV1>>;
        idField?: keyof TFields;
        required: readonly (keyof TFields)[];
        readOnly: readonly (keyof TFields)[];
        containerFields: readonly (keyof TFields)[];
        fmfIds?: Record<keyof TFields, `FMFID:${string}`>;
    };
    constructor(config: {
        name: TName;
        entityId?: `FMTID:${string}`;
        useEntityIds?: boolean;
        comment?: string;
        schema: Partial<Record<keyof TFields, StandardSchemaV1>>;
        fields: TFields;
        navigationPaths: TNavigationPaths;
        defaultSelect: "all" | "schema" | Record<string, Column<any, any, TName>>;
        baseTableConfig: {
            schema: Partial<Record<keyof TFields, StandardSchemaV1>>;
            inputSchema?: Partial<Record<keyof TFields, StandardSchemaV1>>;
            idField?: keyof TFields;
            required: readonly (keyof TFields)[];
            readOnly: readonly (keyof TFields)[];
            containerFields: readonly (keyof TFields)[];
            fmfIds?: Record<keyof TFields, `FMFID:${string}`>;
        };
    });
}
/**
 * Type helper to extract the column map from fields.
 * Table name is baked into each column type for validation.
 * Container fields are marked with IsContainer=true.
 * Columns include both output type (for reading) and input type (for writing/filtering).
 */
export type ColumnMap<TFields extends Record<string, FieldBuilder<any, any, any, any>>, TName extends string> = {
    [K in keyof TFields]: Column<InferFieldOutput<TFields[K]>, InferFieldInput<TFields[K]>, TName, IsContainerField<TFields[K]>>;
};
/**
 * Extract only selectable (non-container) columns from a table.
 * This is used to prevent selecting container fields in queries.
 */
export type SelectableColumnMap<TFields extends Record<string, FieldBuilder<any, any, any, any>>, TName extends string> = {
    [K in SelectableFieldKeys<TFields>]: Column<InferFieldOutput<TFields[K]>, InferFieldInput<TFields[K]>, TName, false>;
};
/**
 * Validates that a select object doesn't contain container field columns.
 * Returns never if any container fields are found, otherwise returns the original type.
 */
export type ValidateNoContainerFields<TSelect extends Record<string, Column<any, any, any, any>>> = {
    [K in keyof TSelect]: TSelect[K] extends Column<any, any, any, true> ? never : TSelect[K];
} extends TSelect ? TSelect : {
    [K in keyof TSelect]: TSelect[K] extends Column<any, any, any, true> ? "❌ Container fields cannot be selected. Use .getSingleField() instead." : TSelect[K];
};
/**
 * Complete table type with both metadata (via Symbols) and column accessors.
 * This is the return type of fmTableOccurrence - users see columns directly,
 * but internal config is hidden via Symbols.
 */
export type FMTableWithColumns<TFields extends Record<string, FieldBuilder<any, any, any, any>>, TName extends string, TNavigationPaths extends readonly string[] = readonly string[]> = FMTable<TFields, TName, TNavigationPaths> & ColumnMap<TFields, TName>;
/**
 * Options for fmTableOccurrence function.
 * Provides autocomplete-friendly typing while preserving inference for navigationPaths.
 */
export interface FMTableOccurrenceOptions<TFields extends Record<string, FieldBuilder<any, any, any, any>>, TName extends string> {
    /** The entity ID (FMTID) for this table occurrence */
    entityId?: `FMTID:${string}`;
    /** The comment for this table */
    comment?: string;
    /**
     * Default select behavior:
     * - "all": Select all fields (including related tables)
     * - "schema": Select only schema-defined fields (default)
     * - function: Custom selection from columns
     */
    defaultSelect?: "all" | "schema" | ((columns: ColumnMap<TFields, TName>) => Record<string, Column<any, any, TName>>);
    /** Navigation paths available from this table (for expand operations) */
    navigationPaths?: readonly string[];
    /** Whether to use entity IDs (FMTID/FMFID) instead of names in queries */
    useEntityIds?: boolean;
}
/**
 * Create a table occurrence with field builders.
 * This is the main API for defining tables in the new ORM style.
 *
 * @example
 * const users = fmTableOccurrence("users", {
 *   id: textField().primaryKey().entityId("FMFID:1"),
 *   name: textField().notNull().entityId("FMFID:6"),
 *   active: numberField()
 *     .outputValidator(z.coerce.boolean())
 *     .inputValidator(z.boolean().transform(v => v ? 1 : 0))
 *     .entityId("FMFID:7"),
 * }, {
 *   entityId: "FMTID:100",
 *   defaultSelect: "schema",
 *   navigationPaths: ["contacts"],
 * });
 *
 * // Access columns
 * users.id    // Column<string, "id">
 * users.name  // Column<string, "name">
 *
 * // Use in queries
 * db.from(users).select("id", "name").where(eq(users.active, true))
 */
export declare function fmTableOccurrence<const TName extends string, const TFields extends Record<string, FieldBuilder<any, any, any, any>>, const TNavPaths extends readonly string[] = readonly []>(name: TName, fields: TFields, options?: FMTableOccurrenceOptions<TFields, TName> & {
    /** Navigation paths available from this table (for expand operations) */
    navigationPaths?: TNavPaths;
}): FMTableWithColumns<TFields, TName, TNavPaths>;
/**
 * Helper to extract the schema type from a TableOccurrence or FMTable.
 */
export type InferTableSchema<T> = T extends FMTable<infer TFields, any> ? InferSchemaFromFields<TFields> : never;
/**
 * Extract the schema type from an FMTable instance.
 * This is used to infer the schema from table objects passed to db.from(), expand(), etc.
 */
export type InferSchemaOutputFromFMTable<T extends FMTable<any, any>> = T extends FMTable<infer TFields, any> ? InferSchemaFromFields<TFields> : never;
/**
 * Extract the input schema type from an FMTable instance.
 * This is used for insert and update operations where we need write types.
 */
export type InferInputSchemaFromFMTable<T extends FMTable<any, any>> = T extends FMTable<infer TFields, any> ? InferInputSchemaFromFields<TFields> : never;
/**
 * Helper type to check if a FieldBuilder's input type excludes null and undefined.
 * This checks the TInput type parameter, which preserves nullability from notNull().
 */
type FieldInputExcludesNullish<F> = F extends FieldBuilder<any, infer TInput, any> ? null extends TInput ? false : undefined extends TInput ? false : true : false;
/**
 * Check if a FieldBuilder is readOnly at the type level
 */
type IsFieldReadOnly<F> = F extends FieldBuilderType<any, any, any, infer ReadOnly> ? (ReadOnly extends true ? true : false) : false;
/**
 * Compute insert data type from FMTable, making notNull fields required.
 * Fields are required if their FieldBuilder's TInput type excludes null/undefined.
 * All other fields are optional (can be omitted).
 * readOnly fields are excluded (including primaryKey/idField since they're automatically readOnly).
 */
export type InsertDataFromFMTable<T extends FMTable<any, any>> = T extends FMTable<infer TFields, any> ? {
    [K in keyof TFields as IsFieldReadOnly<TFields[K]> extends true ? never : FieldInputExcludesNullish<TFields[K]> extends true ? K : never]: InferFieldInput<TFields[K]>;
} & {
    [K in keyof TFields as IsFieldReadOnly<TFields[K]> extends true ? never : FieldInputExcludesNullish<TFields[K]> extends true ? never : K]?: InferFieldInput<TFields[K]>;
} : never;
/**
 * Compute update data type from FMTable.
 * All fields are optional, but readOnly fields are excluded (including primaryKey/idField).
 */
export type UpdateDataFromFMTable<T extends FMTable<any, any>> = T extends FMTable<infer TFields, any> ? {
    [K in keyof TFields as IsFieldReadOnly<TFields[K]> extends true ? never : K]?: InferFieldInput<TFields[K]>;
} : never;
/**
 * Extract the table name type from an FMTable.
 * This is a workaround since we can't directly index Symbols in types.
 */
export type ExtractTableName<T extends FMTable<any, any>> = T extends FMTable<any, infer Name> ? Name : never;
/**
 * Validates that a target table's name matches one of the source table's navigationPaths.
 * Used to ensure type-safe expand/navigate operations.
 */
export type ValidExpandTarget<SourceTable extends FMTable<any, any, any> | undefined, TargetTable extends FMTable<any, any, any>> = SourceTable extends FMTable<any, any, infer SourceNavPaths> ? ExtractTableName<TargetTable> extends SourceNavPaths[number] ? TargetTable : never : TargetTable;
/**
 * Get the table name from an FMTable instance.
 * @param table - FMTable instance
 * @returns The table name
 */
export declare function getTableName<T extends FMTable<any, any>>(table: T): string;
/**
 * Get the entity ID (FMTID) from an FMTable instance.
 * @param table - FMTable instance
 * @returns The entity ID or undefined if not using entity IDs
 */
export declare function getTableEntityId<T extends FMTable<any, any>>(table: T): string | undefined;
/**
 * Get the schema validator from an FMTable instance.
 * @param table - FMTable instance
 * @returns The StandardSchemaV1 validator record (partial - only fields with validators)
 */
export declare function getTableSchema<T extends FMTable<any, any>>(table: T): Partial<Record<keyof T[typeof FMTableFields], StandardSchemaV1>>;
/**
 * Get the fields from an FMTable instance.
 * @param table - FMTable instance
 * @returns The fields record
 */
export declare function getTableFields<T extends FMTable<any, any>>(table: T): any;
/**
 * Get the navigation paths from an FMTable instance.
 * @param table - FMTable instance
 * @returns Array of navigation path names
 */
export declare function getNavigationPaths<T extends FMTable<any, any>>(table: T): readonly string[];
/**
 * Get the default select configuration from an FMTable instance.
 * @param table - FMTable instance
 * @returns Default select configuration
 */
export declare function getDefaultSelect<T extends FMTable<any, any>>(table: T): "all" | "schema" | Record<string, Column<any, any, any, false>>;
/**
 * Get the base table configuration from an FMTable instance.
 * This provides access to schema, idField, required fields, readOnly fields, and field IDs.
 * @param table - FMTable instance
 * @returns Base table configuration object
 */
export declare function getBaseTableConfig<T extends FMTable<any, any>>(table: T): {
    schema: Partial<Record<string | number | symbol, StandardSchemaV1<unknown, unknown>>>;
    inputSchema?: Partial<Record<string | number | symbol, StandardSchemaV1<unknown, unknown>>> | undefined;
    idField?: string | number | symbol | undefined;
    required: readonly (string | number | symbol)[];
    readOnly: readonly (string | number | symbol)[];
    containerFields: readonly (string | number | symbol)[];
    fmfIds?: Record<string | number | symbol, `FMFID:${string}`> | undefined;
};
/**
 * Check if an FMTable instance is using entity IDs (both FMTID and FMFIDs).
 * @param table - FMTable instance
 * @returns True if using entity IDs, false otherwise
 */
export declare function isUsingEntityIds<T extends FMTable<any, any>>(table: T): boolean;
/**
 * Get the field ID (FMFID) for a given field name, or the field name itself if not using IDs.
 * @param table - FMTable instance
 * @param fieldName - Field name to get the ID for
 * @returns The FMFID string or the original field name
 */
export declare function getFieldId<T extends FMTable<any, any>>(table: T, fieldName: string): string;
/**
 * Get the field name for a given field ID (FMFID), or the ID itself if not found.
 * @param table - FMTable instance
 * @param fieldId - The FMFID to get the field name for
 * @returns The field name or the original ID
 */
export declare function getFieldName<T extends FMTable<any, any>>(table: T, fieldId: string): string;
/**
 * Get the table ID (FMTID or name) from an FMTable instance.
 * Returns the FMTID if available, otherwise returns the table name.
 * @param table - FMTable instance
 * @returns The FMTID string or the table name
 */
export declare function getTableId<T extends FMTable<any, any>>(table: T): string;
/**
 * Get the comment from an FMTable instance.
 * @param table - FMTable instance
 * @returns The comment string or undefined if not set
 */
export declare function getTableComment<T extends FMTable<any, any>>(table: T): string | undefined;
/**
 * Get all columns from a table as an object.
 * Useful for selecting all fields except some using destructuring.
 *
 * @example
 * const { password, ...cols } = getTableColumns(users)
 * db.from(users).list().select(cols)
 *
 * @param table - FMTable instance
 * @returns Object with all columns from the table
 */
export declare function getTableColumns<T extends FMTable<any, any>>(table: T): ColumnMap<T[typeof FMTableFields], ExtractTableName<T>>;
export {};
