import { FieldsSchema } from './schema.js';
export { fieldGroups, fieldValues, fieldsSchema } from './schema.js';
export { fieldsMigrationSql } from './migrate.js';
import { Querier, TransactionalDatabase } from '@platform-modules/db';
import 'drizzle-orm/pg-core';

type EntityType = string;
type EntityId = string;
interface EntityRef {
    entityType: EntityType;
    entityId: EntityId;
}
interface LocationRule {
    entityType: EntityType;
    subType?: string;
}
declare const FIELD_TYPES: readonly ["text", "textarea", "number", "boolean", "select", "date", "color", "url", "email", "media", "relationship"];
type FieldType = (typeof FIELD_TYPES)[number];
/** stable machine key + storage/read key */
declare const FIELD_KEY_RE: RegExp;
declare function isMultipleCapable(t: FieldType): boolean;
type MediaRef = {
    key: string;
    url?: string;
    mime?: string;
    meta?: Record<string, unknown>;
};
type RelRef = EntityRef;
type ScalarValue = string | number | boolean | Date | MediaRef | RelRef;
type FieldValue = ScalarValue | ScalarValue[];
type FieldValueMap = Record<string, FieldValue | undefined>;
interface BaseField {
    key: string;
    label: string;
    required?: boolean;
    help?: string;
    defaultValue?: FieldValue;
}
interface TextField extends BaseField {
    type: 'text';
    maxLength?: number;
    pattern?: string;
}
interface TextAreaField extends BaseField {
    type: 'textarea';
    maxLength?: number;
}
interface NumberField extends BaseField {
    type: 'number';
    min?: number;
    max?: number;
    integer?: boolean;
}
interface BooleanField extends BaseField {
    type: 'boolean';
}
interface SelectField extends BaseField {
    type: 'select';
    options: {
        value: string;
        label: string;
    }[];
    multiple?: boolean;
}
interface DateField extends BaseField {
    type: 'date';
}
interface ColorField extends BaseField {
    type: 'color';
}
interface UrlField extends BaseField {
    type: 'url';
}
interface EmailField extends BaseField {
    type: 'email';
}
interface MediaField extends BaseField {
    type: 'media';
    accept?: string[];
    multiple?: boolean;
}
interface RelationshipField extends BaseField {
    type: 'relationship';
    targetEntityType: EntityType;
    multiple?: boolean;
}
type FieldDefinition = TextField | TextAreaField | NumberField | BooleanField | SelectField | DateField | ColorField | UrlField | EmailField | MediaField | RelationshipField;
interface FieldGroup {
    key: string;
    label: string;
    location: LocationRule;
    fields: FieldDefinition[];
    position?: number;
}
type FieldOrigin = 'code' | 'db';
interface ResolvedFieldGroup extends FieldGroup {
    origin: FieldOrigin;
    id?: string;
}
interface Actor {
    id: string;
    canEditFields?: boolean;
    canManageGroups?: boolean;
}
type Facet = {
    field: string;
    op: 'eq' | 'in';
    value: string | string[];
} | {
    field: string;
    op: 'eq' | 'lt' | 'lte' | 'gt' | 'gte';
    value: number;
} | {
    field: string;
    op: 'between';
    min: number;
    max: number;
} | {
    field: string;
    op: 'has-ref';
    refType: EntityType;
    refId: EntityId;
};
type RelRefResolver = (ref: EntityRef) => Promise<boolean>;

declare class FieldValidationError extends Error {
    readonly field: string;
    readonly detail: string;
    readonly name = "FieldValidationError";
    constructor(field: string, detail: string);
}
declare class FieldGroupConflictError extends Error {
    readonly key: string;
    readonly detail: string;
    readonly name = "FieldGroupConflictError";
    constructor(key: string, detail: string);
}
declare class FieldAuthorizationError extends Error {
    readonly actorId: string;
    readonly action: string;
    readonly name = "FieldAuthorizationError";
    constructor(actorId: string, action: string);
}
declare class FieldStoreError extends Error {
    readonly detail: string;
    readonly name = "FieldStoreError";
    constructor(detail: string);
}
declare const isFieldValidationError: (e: unknown) => e is FieldValidationError;
declare const isFieldGroupConflictError: (e: unknown) => e is FieldGroupConflictError;
declare const isFieldAuthorizationError: (e: unknown) => e is FieldAuthorizationError;
declare const isFieldStoreError: (e: unknown) => e is FieldStoreError;

declare function assertCanEditFields(actor: Actor): void;
declare function assertCanManageGroups(actor: Actor): void;

/** Pure, validator-agnostic. Throws FieldValidationError on first offending field.
 *  Does NOT check relationship existence (that is setEntityValues' optional async resolver, §6). */
declare function validateValues(group: ResolvedFieldGroup, values: FieldValueMap): void;

type CodeFieldGroup = FieldGroup & {
    readonly origin: 'code';
};
type ScalarInfer<F extends FieldDefinition> = F extends {
    type: 'text' | 'textarea' | 'color' | 'url' | 'email';
} ? string : F extends {
    type: 'number';
} ? number : F extends {
    type: 'boolean';
} ? boolean : F extends {
    type: 'date';
} ? Date : F extends {
    type: 'media';
} ? MediaRef : F extends {
    type: 'relationship';
} ? RelRef : F extends {
    type: 'select';
} ? string : never;
type FieldValueInfer<F extends FieldDefinition> = F extends {
    multiple: true;
} ? ScalarInfer<F>[] : ScalarInfer<F>;
type InferValues<G extends CodeFieldGroup> = {
    [F in G['fields'][number] as F['key']]: FieldValueInfer<F>;
};
declare function defineFieldGroup(group: FieldGroup): CodeFieldGroup;
declare function assertNoCrossGroupFieldKeyConflict(groups: ResolvedFieldGroup[]): void;
declare function assertNoCodeKeyShadow(dbKey: string, entityType: EntityType, codeGroups: CodeFieldGroup[] | undefined): void;
declare function resolveGroups(db: Querier<FieldsSchema>, opts: {
    entityType: EntityType;
    subType?: string;
    codeGroups?: CodeFieldGroup[];
}): Promise<ResolvedFieldGroup[]>;
declare function typedValues<G extends CodeFieldGroup>(group: G, map: FieldValueMap): InferValues<G>;

declare function getEntityValues(db: Querier<FieldsSchema>, ref: EntityRef, opts: {
    entityType: string;
    subType?: string;
    codeGroups?: CodeFieldGroup[];
}): Promise<FieldValueMap>;
declare function setEntityValues(db: TransactionalDatabase<FieldsSchema>, actor: Actor, input: {
    ref: EntityRef;
    groupId: string;
    values: FieldValueMap;
    resolved: ResolvedFieldGroup;
    resolveRef?: RelRefResolver;
}): Promise<void>;
/**
 * Host-cascade op: removes ALL field values for an entity (call on parent-entity delete, spec §8.1).
 * Takes NO `Actor` and runs NO capability check by design — so the HOST MUST gate BOTH capability
 * AND object-level ownership BEFORE calling this. The engine never knows who owns `entityId`
 * (no owner column; spec §5). Never assume the engine authorizes this delete.
 */
declare function deleteEntityValues(db: Querier<FieldsSchema>, ref: EntityRef): Promise<void>;
declare function createGroup(db: Querier<FieldsSchema>, actor: Actor, group: FieldGroup, codeGroups?: CodeFieldGroup[]): Promise<ResolvedFieldGroup>;
declare function updateGroup(db: Querier<FieldsSchema>, actor: Actor, id: string, patch: Partial<FieldGroup>, codeGroups?: CodeFieldGroup[]): Promise<ResolvedFieldGroup>;
declare function deleteGroup(db: Querier<FieldsSchema>, actor: Actor, id: string): Promise<void>;
declare function listGroups(db: Querier<FieldsSchema>, opts: {
    entityType?: string;
    subType?: string;
}): Promise<ResolvedFieldGroup[]>;

/**
 * Returns a capped candidate entity-id set for cross-module faceting (spec §5.4).
 * `capped: true` is a correctness boundary — the candidate set is intermediate; when
 * capped, the host MUST NOT present the intersected result as authoritative (degrade
 * explicitly). The cap is a v1 expedient; high-cardinality push-down is deferred.
 *
 * All facet/entity inputs are bound as query parameters (NOT string-interpolated):
 * facet values are user-facing (storefront filters, §8.2) → a trust boundary, so the
 * SQL is built from drizzle `sql` fragments with `${}` parameter placeholders only.
 */
declare function queryEntities(db: Querier<FieldsSchema>, q: {
    entityType: EntityType;
    facets: Facet[];
    limit?: number;
}): Promise<{
    entityIds: EntityId[];
    capped: boolean;
}>;

export { type Actor, type BaseField, type BooleanField, type CodeFieldGroup, type ColorField, type DateField, type EmailField, type EntityId, type EntityRef, type EntityType, FIELD_KEY_RE, FIELD_TYPES, type Facet, FieldAuthorizationError, type FieldDefinition, type FieldGroup, FieldGroupConflictError, type FieldOrigin, FieldStoreError, type FieldType, FieldValidationError, type FieldValue, type FieldValueMap, FieldsSchema, type InferValues, type LocationRule, type MediaField, type MediaRef, type NumberField, type RelRef, type RelRefResolver, type RelationshipField, type ResolvedFieldGroup, type ScalarValue, type SelectField, type TextAreaField, type TextField, type UrlField, assertCanEditFields, assertCanManageGroups, assertNoCodeKeyShadow, assertNoCrossGroupFieldKeyConflict, createGroup, defineFieldGroup, deleteEntityValues, deleteGroup, getEntityValues, isFieldAuthorizationError, isFieldGroupConflictError, isFieldStoreError, isFieldValidationError, isMultipleCapable, listGroups, queryEntities, resolveGroups, setEntityValues, typedValues, updateGroup, validateValues };
