import { NodePgDatabase } from 'drizzle-orm/node-postgres';
import { PgliteDatabase } from 'drizzle-orm/pglite';
import DataLoader from 'dataloader';
import { TableRelationalConfig } from 'drizzle-orm';
import { TableConfig, PgTableExtraConfig, PgTable } from 'drizzle-orm/pg-core';
import { GraphQLSchema } from 'graphql';

type SubgraphMetaBlock = {
    /** Block number */
    number: bigint;
    /** Block unix timestamp */
    timestamp: bigint;
    /** Block hash */
    hash: `0x${string}`;
    /** Block parent hash */
    parentHash: `0x${string}`;
};
/**
 * The metadata provider interface used to fetch data from the application layer.
 */
interface PonderMetadataProvider {
    /**
     * ENSIndexer app version.
     */
    version: string;
    /**
     * Get last indexed block status
     * @returns The last indexed block status
     */
    getLastIndexedDeploymentChainBlock(): Promise<SubgraphMetaBlock>;
    /**
     * Get the Ponder build ID
     * @returns The Ponder build ID
     */
    getPonderBuildId(): Promise<string>;
    /**
     * Get the indexing errors status
     * @returns The indexing errors status
     */
    hasIndexingErrors: () => Promise<boolean>;
}

/**
 * This is a graphql schema generated from a drizzle (sql) schema, initially based on ponder's.
 * https://github.com/ponder-sh/ponder/blob/main/packages/core/src/graphql/index.ts
 *
 * Its goal is to mimic the subgraph graphql api for queries we've deemed relevant (see docs).
 *
 * 1. inlines some ponder internal types
 * 2. implement subgraph's simpler offset pagination with first & skip w/out Page types
 * 3. PascalCase entity names
 * 4. Polymorphic Interfaces
 * 5. lower-case and/or filters
 * 6. relation id shorthand filters (i.e. domains(where: { owner_id: String }))
 * 7. sortable id columns
 * 8. temporarily ignores column normalization that was fixed in
 *    https://github.com/ponder-sh/ponder/pull/1517/files
 */

type Drizzle<TSchema extends Schema = {
    [name: string]: never;
}> = NodePgDatabase<TSchema> | PgliteDatabase<TSchema>;
type Schema = {
    [name: string]: unknown;
};
declare const onchain: unique symbol;
type OnchainTable<T extends TableConfig & {
    extra: PgTableExtraConfig | undefined;
} = TableConfig & {
    extra: PgTableExtraConfig | undefined;
}> = PgTable<T> & {
    [Key in keyof T["columns"]]: T["columns"][Key];
} & {
    [onchain]: true;
} & {
    enableRLS: () => Omit<OnchainTable<T>, "enableRLS">;
};

/**
 * the following type describes:
 * 1. `types` — mapping a polymorphic type name to the set of entities that implement that interface
 *   ex: DomainEvent -> [TransferEvent, ...]
 * 2. `fields` — mapping a typeName to the polymorphic type it represents
 *   ex: Domain.events -> DomainEvent
 *
 * NOTE: in future implementations of ponder, this information could be provided by the schema
 * using materialized views, and most/all of this code can be removed.
 */
interface PolymorphicConfig {
    types: Record<string, PgTable<TableConfig>[]>;
    fields: Record<string, string>;
}
interface BuildGraphQLSchemaOptions {
    schema: Schema;
    polymorphicConfig?: PolymorphicConfig;
    metadataProvider: PonderMetadataProvider;
}
declare function buildGraphQLSchema({ schema: _schema, polymorphicConfig: _polymorphicConfig, metadataProvider, }: BuildGraphQLSchemaOptions): GraphQLSchema;
declare function buildDataLoaderCache({ drizzle }: {
    drizzle: Drizzle<Schema>;
}): ({ table }: {
    table: TableRelationalConfig;
}) => DataLoader<string, any, string>;

export { type Drizzle, type OnchainTable, type PolymorphicConfig, type Schema, buildDataLoaderCache, buildGraphQLSchema, onchain };
