import { GenericId } from '@convex-dev/common';
import { Value } from '@convex-dev/common';

/**
 * Internal type used in Convex code generation!
 *
 * Convert a {@link SchemaDefinition} into a {@link server.GenericDataModel}.
 *
 * @public
 */
export declare type DataModelFromSchemaDefinition<SchemaDef extends SchemaDefinition<any>> = SchemaDef extends SchemaDefinition<infer Schema> ? {
    [TableName in keyof Schema & string]: Schema[TableName] extends TableDefinition<infer Document, infer FieldPaths, infer TableIndexes> ? {
        document: Expand<IdField<TableName> & Document>;
        fieldPaths: keyof IdField<TableName> | FieldPaths;
        indexes: Expand<TableIndexes & SystemIndexes>;
    } : never;
} : never;

/**
 * Define the schema of this Convex project.
 *
 * This should be exported from a `schema.ts` file in your `convex/` directory
 * like:
 *
 * ```ts
 * export default defineSchema({
 *   ...
 * });
 * ```
 *
 * @param schema - A map from table name to {@link TableDefinition} for all of
 * the tables in this project.
 * @returns The schema.
 *
 * @public
 */
export declare function defineSchema<Schema extends GenericSchema>(schema: Schema): SchemaDefinition<Schema>;

/**
 * Define a table in a schema.
 *
 * You can either specify the schema of your documents as an object like
 * ```ts
 * defineTable({
 *   field: s.string()
 * });
 * ```
 *
 * or as a schema type like
 * ```ts
 * defineTable(s.object({
 *   field: s.string()
 * }));
 * ```
 *
 * @param documentSchema - The type of documents stored in this table.
 * @returns A {@link TableDefinition} for the table.
 *
 * @public
 */
export declare function defineTable<DocumentSchema extends SchemaType<Record<string, any>, any>>(documentSchema: DocumentSchema): TableDefinition<ExtractDocument<DocumentSchema>, ExtractFieldPaths<DocumentSchema>>;

/**
 * Define a table in a schema.
 *
 * You can either specify the schema of your documents as an object like
 * ```ts
 * defineTable({
 *   field: s.string()
 * });
 * ```
 *
 * or as a schema type like
 * ```ts
 * defineTable(s.object({
 *   field: s.string()
 * }));
 * ```
 *
 * @param documentSchema - The type of documents stored in this table.
 * @returns A {@link TableDefinition} for the table.
 *
 * @public
 */
export declare function defineTable<DocumentSchema extends Record<string, SchemaType<any, any>>>(documentSchema: DocumentSchema): TableDefinition<ExtractDocument<ObjectSchemaType<DocumentSchema>>, ExtractFieldPaths<ObjectSchemaType<DocumentSchema>>>;

/**
 * Internal type used in Convex code generation!
 *
 * Convert a {@link SchemaDefinition} into an object type that maps table names
 * to their document types.
 *
 * This is similar to {@link server.GenericDataModel} but it doesn't contain
 * index information. This is nice for making some types appear simpler in
 * VSCode.
 *
 * @public
 */
export declare type DocumentMapFromSchemaDefinition<SchemaDef extends SchemaDefinition<any>> = SchemaDef extends SchemaDefinition<infer Schema> ? {
    [TableName in keyof Schema & string]: Schema[TableName] extends TableDefinition<infer Document, any, any> ? Expand<IdField<TableName> & Document> : never;
} : never;

/**
 * Common utilities for manipulating TypeScript types.
 * @module
 */
/**
 * Hack! This type causes TypeScript to simplify how it renders object types.
 *
 * It is functionally the identity for object types, but in practice it can
 * simplify expressions like `A & B`.
 */
declare type Expand<ObjectType extends Record<any, any>> = ObjectType extends Record<any, any> ? {
    [Key in keyof ObjectType]: ObjectType[Key];
} : never;

/**
 * Extract the {@link GenericDocument} within a {@link SchemaType} and
 * add on the system fields.
 *
 * This is used within {@link defineTable}.
 * @public
 */
declare type ExtractDocument<T extends SchemaType<any, any>> = T extends SchemaType<infer Value, any> ? Value extends GenericDocument ? Expand<SystemFields & Value> : never : never;

/**
 * Extract all of the index field paths within a {@link SchemaType}.
 *
 * This is used within {@link defineTable}.
 * @public
 */
declare type ExtractFieldPaths<T extends SchemaType<any, any>> = T extends SchemaType<any, infer FieldPaths> ? // Add in the system fields available in index definitions.
FieldPaths | keyof SystemFields : never;

/**
 * A document stored in Convex.
 * @public
 */
declare type GenericDocument = Record<string, Value>;

/**
 * A type describing the ordered fields in an index.
 *
 * These can either be field names (like "name") or references to fields on
 * nested objects (like "properties.name").
 * @public
 */
declare type GenericIndexFields = string[];

/**
 * A type describing the schema of a Convex project.
 *
 * This should be constructed using {@link defineSchema}, {@link defineTable},
 * and {@link s}.
 * @public
 */
export declare type GenericSchema = Record<string, TableDefinition>;

/**
 * A type describing the indexes in a table.
 *
 * It's a map from index name to fields in the index.
 * @public
 */
declare type GenericTableIndexes = Record<string, GenericIndexFields>;

/**
 * The `_id` field that Convex automatically adds to documents.
 * @public
 */
declare type IdField<TableName extends string> = {
    _id: GenericId<TableName>;
};

/**
 * Join together two index field paths.
 *
 * This is used within the SchemaBuilder {@link s}.
 * @public
 */
declare type JoinFieldPaths<Start extends string, End extends string> = `${Start}.${End}`;

/**
 * Calculate the {@link SchemaType} for an object.
 *
 * This is used within the SchemaBuilder {@link s}.
 * @public
 */
declare type ObjectSchemaType<SchemaValueType extends Record<string, SchemaType<any, any>>> = SchemaType<{
    [Property in keyof SchemaValueType]: SchemaValueType[Property] extends SchemaType<infer InnerType, any> ? InnerType : never;
}, {
    [Property in keyof SchemaValueType]: SchemaValueType[Property] extends SchemaType<any, infer FieldPaths> ? JoinFieldPaths<Property & string, FieldPaths> | Property : never;
}[keyof SchemaValueType] & string>;

/**
 * The schema builder.
 *
 * This builder allows you to define the types of documents stored in Convex.
 * @public
 */
export declare const s: {
    id<TableName extends string>(tableName: TableName): SchemaType<GenericId<TableName>, never>;
    null(): SchemaType<null, never>;
    number(): SchemaType<number, never>;
    bigint(): SchemaType<bigint, never>;
    boolean(): SchemaType<boolean, never>;
    string(): SchemaType<string, never>;
    bytes(): SchemaType<ArrayBuffer, never>;
    literal<T extends string | number | bigint | boolean>(literal: T): SchemaType<T, never>;
    array<T_1>(values: SchemaType<T_1, any>): SchemaType<T_1[], never>;
    set<T_2>(values: SchemaType<T_2, any>): SchemaType<Set<T_2>, never>;
    map<K, V>(keys: SchemaType<K, any>, values: SchemaType<V, any>): SchemaType<Map<K, V>, never>;
    object<T_3 extends Record<string, SchemaType<any, any>>>(schema: T_3): ObjectSchemaType<T_3>;
    union<T_4 extends [SchemaType<any, any>, SchemaType<any, any>, ...SchemaType<any, any>[]]>(...schemaTypes: T_4): SchemaType<T_4[number]["type"], T_4[number]["fieldPaths"]>;
};

/**
 *
 * The definition of a Convex project schema.
 *
 * This should be produced by using {@link defineSchema}.
 * @public
 */
export declare class SchemaDefinition<Schema extends GenericSchema> {
    private tables;
    /**
     * @internal
     */
    constructor(tables: Schema);
    /**
     * Export the contents of this definition.
     *
     * This is called internally by the Convex framework.
     * @internal
     */
    export(): string;
}

/**
 * A Convex type defined in a schema.
 *
 * These should be constructed using {@link s}.
 *
 * This class encapsulates:
 * - The TypeScript type of this Convex type.
 * - The TypeScript type for the set of index field paths that can be used to
 * build indexes on this type.
 * - The table names referenced in `s.id` usages in this type.
 * @public
 */
export declare class SchemaType<TypeScriptType, FieldPaths extends string> {
    readonly type: TypeScriptType;
    readonly fieldPaths: FieldPaths;
    private _isSchemaType;
    readonly referencedTableNames: Set<string>;
    constructor(referencedTableNames?: Set<string>);
}

/**
 * The fields that Convex automatically adds to documents, not including `_id`.
 *
 * This is an object type mapping field name to field type.
 * @public
 */
declare type SystemFields = {
    _creationTime: number;
};

/**
 * The indexes that Convex automatically adds to every table.
 *
 * This is an object mapping index names to index field paths.
 * @public
 */
declare type SystemIndexes = {
    by_creation_time: ["_creationTime"];
};

/**
 * The definition of a table within a schema.
 *
 * This should be produced by using {@link defineTable}.
 * @public
 */
export declare class TableDefinition<Document extends GenericDocument = GenericDocument, FieldPaths extends string = string, TableIndexes extends GenericTableIndexes = {}> {
    private indexes;
    private documentType;
    /**
     * @internal
     */
    constructor(documentType: SchemaType<any, any>);
    /**
     * Define an index on this table.
     *
     * To learn about indexes, see [Defining Indexes](https://docs.convex.dev/using/indexes).
     *
     * @param name - The name of the index.
     * @param fields - The fields to index, in order. Must specify at least one
     * field.
     * @returns A {@link TableDefinition} with this index included.
     */
    index<IndexName extends string, FirstFieldPath extends FieldPaths, RestFieldPaths extends FieldPaths[]>(name: IndexName, fields: [FirstFieldPath, ...RestFieldPaths]): TableDefinition<Document, FieldPaths, Expand<TableIndexes & Record<IndexName, [FirstFieldPath, ...RestFieldPaths]>>>;
    /**
     * Export the contents of this definition.
     *
     * This is called internally by the Convex framework.
     * @internal
     */
    export(): {
        indexes: {
            indexDescriptor: string;
            fields: string[];
        }[];
        referencedTableNames: Set<string>;
    };
}

export { }
