import { SQL as BunSQL, type SQLQuery } from 'bun';
import type { PostgresConfig, ConnectionStats, TransactionOptions, ReserveOptions, UnsafeQueryResult } from './types.ts';
import { Transaction, ReservedConnection } from './transaction.ts';
/**
 * Creates a lazy thenable with format locking for safe query execution.
 *
 * The returned object implements the {@link UnsafeQueryResult} interface: it is
 * thenable (`.then()`, `.catch()`, `.finally()`) and exposes a `.values()`
 * method for array-format results. Execution is deferred until the first
 * consumption method is called.
 *
 * **Format locking:** The first access (`.then()` or `.values()`) determines
 * the result format for the lifetime of the thenable. Attempting the other
 * format afterwards throws an error, preventing accidental duplicate execution.
 *
 * @param makeExecutor - Factory that creates the execution promise.
 *   Called with `true` for array format (`.values()`) or `false` for row-object
 *   format (`.then()`).
 * @returns A lazy thenable with `.values()` support
 *
 * @internal Exported for use by `@agentuity/drizzle` — not part of the public API.
 */
export declare function createThenable(makeExecutor: (useValues: boolean) => Promise<unknown>): UnsafeQueryResult;
/**
 * A resilient PostgreSQL client with automatic reconnection.
 *
 * Wraps Bun's native SQL driver and adds:
 * - Automatic reconnection with exponential backoff
 * - Connection state tracking
 * - Transaction support
 * - Reserved connection support
 *
 * Can be used as a tagged template literal for queries:
 *
 * @example
 * ```typescript
 * const client = new PostgresClient();
 *
 * // Simple query
 * const users = await client`SELECT * FROM users`;
 *
 * // Parameterized query
 * const user = await client`SELECT * FROM users WHERE id = ${userId}`;
 *
 * // Transaction
 * const tx = await client.begin();
 * await tx`INSERT INTO users (name) VALUES (${name})`;
 * await tx.commit();
 * ```
 */
export declare class PostgresClient {
    private _sql;
    private _config;
    private _initialized;
    private _connected;
    private _reconnecting;
    private _closed;
    private _shuttingDown;
    private _signalHandlers;
    private _reconnectPromise;
    private _connectPromise;
    private _stats;
    /**
     * Creates a new PostgresClient.
     *
     * Note: By default, the actual TCP connection is established lazily on first query.
     * The `connected` property will be `false` until a query is executed or
     * `waitForConnection()` is called. Set `preconnect: true` in config to
     * establish the connection immediately.
     *
     * @param config - Connection configuration. Can be a connection URL string or a config object.
     *                 If not provided, uses `process.env.DATABASE_URL`.
     */
    constructor(config?: string | PostgresConfig);
    /**
     * Whether the client is currently connected.
     */
    get connected(): boolean;
    /**
     * Whether the client is shutting down (won't attempt reconnection).
     */
    get shuttingDown(): boolean;
    /**
     * Whether a reconnection attempt is in progress.
     */
    get reconnecting(): boolean;
    /**
     * Connection statistics.
     */
    get stats(): Readonly<ConnectionStats>;
    /**
     * Execute a query using tagged template literal syntax.
     * If reconnection is in progress, waits for it to complete before executing.
     * Automatically retries on retryable errors.
     *
     * @example
     * ```typescript
     * const users = await client`SELECT * FROM users WHERE active = ${true}`;
     * ```
     */
    query(strings: TemplateStringsArray, ...values: unknown[]): Promise<unknown[]>;
    /**
     * Begin a new transaction.
     *
     * @param options - Transaction options (isolation level, read-only, deferrable)
     * @returns A Transaction object for executing queries within the transaction
     *
     * @example
     * ```typescript
     * const tx = await client.begin();
     * try {
     *   await tx`INSERT INTO users (name) VALUES (${name})`;
     *   await tx`UPDATE accounts SET balance = balance - ${amount} WHERE id = ${fromId}`;
     *   await tx.commit();
     * } catch (error) {
     *   await tx.rollback();
     *   throw error;
     * }
     * ```
     */
    begin(options?: TransactionOptions): Promise<Transaction>;
    /**
     * Reserve an exclusive connection from the pool.
     *
     * **Note:** This feature is not currently supported because Bun's SQL driver
     * does not expose connection-level pooling APIs. The underlying driver manages
     * connections internally and does not allow reserving a specific connection.
     *
     * @param _options - Reserve options (unused)
     * @throws {UnsupportedOperationError} Always throws - this operation is not supported
     *
     * @example
     * ```typescript
     * // This will throw UnsupportedOperationError
     * const conn = await client.reserve();
     * ```
     */
    reserve(_options?: ReserveOptions): Promise<ReservedConnection>;
    /**
     * Signal that the application is shutting down.
     * This prevents reconnection attempts but doesn't immediately close the connection.
     * Use this when you want to gracefully drain connections before calling close().
     */
    shutdown(): void;
    /**
     * Close the client and release all connections.
     */
    close(): Promise<void>;
    /**
     * Access to raw SQL methods for advanced use cases.
     * Returns the underlying Bun.SQL instance.
     */
    get raw(): InstanceType<typeof BunSQL>;
    /**
     * Execute an unsafe (unparameterized) query.
     * Use with caution - this bypasses SQL injection protection.
     *
     * @param query - The raw SQL query string
     */
    unsafe(query: string): SQLQuery;
    /**
     * Execute a raw SQL query with automatic retry and transaction wrapping for mutations.
     *
     * Unlike {@link unsafe}, this method:
     * - Automatically retries on retryable errors (connection drops, resets)
     * - Wraps mutation statements in transactions for safe retry
     * - Returns a thenable with `.values()` support matching Bun's SQLQuery interface
     *
     * Detected mutation types: INSERT, UPDATE, DELETE, COPY, TRUNCATE, MERGE, CALL, DO.
     * EXPLAIN queries are never wrapped (read-only analysis).
     *
     * For SELECT queries, retries without transaction wrapping (idempotent).
     * For mutations, wraps in BEGIN/COMMIT so PostgreSQL auto-rolls back
     * uncommitted transactions on connection drop, making retry safe.
     *
     * **⚠️ COMMIT Uncertainty Window:**
     * If the connection drops after the server processes COMMIT but before the client
     * receives confirmation (~<1ms window), changes ARE committed but the client sees
     * a failure. Retry will then duplicate the mutation. This is an inherent limitation
     * of retry-based approaches. Use application-level idempotency (e.g., unique
     * constraints with ON CONFLICT) for critical operations.
     *
     * **⚠️ Result Format Locking:**
     * Each unsafeQuery() result can only be consumed via ONE access pattern — either
     * `await result` (row objects) or `await result.values()` (arrays), not both.
     * Attempting the second pattern throws an error to prevent accidental duplicate execution.
     *
     * @param query - The raw SQL query string
     * @param params - Optional query parameters
     * @returns A thenable that resolves to rows (objects) or arrays via `.values()`
     *
     * @see https://github.com/agentuity/sdk/issues/911
     *
     * @example
     * ```typescript
     * // INSERT with safe retry
     * const rows = await client.unsafeQuery('INSERT INTO items (name) VALUES ($1) RETURNING *', ['test']);
     *
     * // SELECT with retry (no transaction overhead)
     * const items = await client.unsafeQuery('SELECT * FROM items WHERE id = $1', [42]);
     *
     * // Get raw arrays via .values()
     * const arrays = await client.unsafeQuery('SELECT id, name FROM items').values();
     * ```
     */
    unsafeQuery(query: string, params?: unknown[]): UnsafeQueryResult;
    /**
     * Registers signal handlers to detect application shutdown.
     * When shutdown is detected, reconnection is disabled.
     */
    private _registerShutdownHandlers;
    /**
     * Removes signal handlers registered for shutdown detection.
     */
    private _removeShutdownHandlers;
    /**
     * Initializes the internal Bun.SQL client.
     * Note: This creates the SQL client but doesn't establish the TCP connection yet.
     * Bun's SQL driver uses lazy connections - the actual TCP connection is made on first query.
     */
    private _initializeSql;
    /**
     * Warms the connection by executing a test query.
     * This establishes the actual TCP connection and verifies it's working.
     */
    private _warmConnection;
    /**
     * Re-initializes the SQL client for reconnection.
     * Used internally during the reconnection loop.
     */
    private _reinitializeSql;
    /**
     * Handles connection close events.
     */
    private _handleClose;
    /**
     * Starts the reconnection process.
     */
    private _startReconnect;
    /**
     * The main reconnection loop with exponential backoff.
     */
    private _reconnectLoop;
    /**
     * Ensures the client is initialized and returns the SQL instance.
     * This is the synchronous version - use _ensureConnectedAsync when you can await.
     *
     * Note: This returns the SQL instance even if `_connected` is false because
     * Bun's SQL uses lazy connections. The actual connection will be established
     * on first query. Use this for synchronous access to the SQL instance.
     */
    private _ensureConnected;
    /**
     * Ensures the client is connected and returns the SQL instance.
     * If reconnection is in progress, waits for it to complete.
     * If connection hasn't been established yet, warms it first.
     */
    private _ensureConnectedAsync;
    /**
     * Executes an operation with retry logic for retryable errors.
     * Waits for reconnection if one is in progress.
     */
    private _executeWithRetry;
    /**
     * Execute an operation with automatic retry on retryable errors.
     * If reconnection is in progress, waits for it to complete before executing.
     *
     * This is the public counterpart of the internal `_executeWithRetry` method,
     * exposed for use by integration layers (e.g. the Drizzle resilient proxy).
     *
     * @param operation - The async operation to execute
     * @param maxRetries - Maximum number of retries (default: 3)
     * @returns The result of the operation
     */
    executeWithRetry<T>(operation: () => T | Promise<T>, maxRetries?: number): Promise<T>;
    /**
     * Wait for the connection to be established.
     * If the connection hasn't been established yet (lazy connection), this will
     * warm the connection by executing a test query.
     * If reconnection is in progress, waits for it to complete.
     *
     * @param timeoutMs - Optional timeout in milliseconds
     * @throws {ConnectionClosedError} If the client has been closed or connection fails
     */
    waitForConnection(timeoutMs?: number): Promise<void>;
}
/**
 * Type for the callable PostgresClient that supports tagged template literals.
 */
export type CallablePostgresClient = PostgresClient & {
    (strings: TemplateStringsArray, ...values: unknown[]): Promise<unknown[]>;
    unsafeQuery(query: string, params?: unknown[]): UnsafeQueryResult;
};
/**
 * Creates a PostgresClient that can be called as a tagged template literal.
 *
 * @param config - Connection configuration
 * @returns A callable PostgresClient
 *
 * @internal
 */
export declare function createCallableClient(config?: string | PostgresConfig): CallablePostgresClient;
//# sourceMappingURL=client.d.ts.map