import { OperatorFunction, Observable } from 'rxjs';
import { AbiEvent } from 'abitype';
import { PublicClient, Address, BlockNumber, GetLogsReturnType, BlockTag, Block } from 'viem';

type FetchLogsOptions<TAbiEvents extends readonly AbiEvent[]> = {
    /**
     * [viem `PublicClient`][0] used for fetching logs from the RPC.
     *
     * [0]: https://viem.sh/docs/clients/public.html
     */
    publicClient: PublicClient;
    /**
     * Optional contract address(es) to fetch logs for.
     */
    address?: Address | Address[];
    /**
     * Events to fetch logs for.
     */
    events: TAbiEvents;
    /**
     * The block number to start fetching logs from (inclusive).
     */
    fromBlock: BlockNumber;
    /**
     * The block number to stop fetching logs at (inclusive).
     */
    toBlock: BlockNumber;
    /**
     * Optional maximum block range, if your RPC limits the amount of blocks fetched at a time. Defaults to 1000n.
     */
    maxBlockRange?: bigint;
    /**
     * Optional maximum amount of retries if the RPC returns a rate limit error. Defaults to 3.
     */
    maxRetryCount?: number;
};
type FetchLogsResult<TAbiEvents extends readonly AbiEvent[]> = {
    fromBlock: BlockNumber;
    toBlock: BlockNumber;
    logs: GetLogsReturnType<undefined, TAbiEvents, true, BlockNumber, BlockNumber>;
};
/**
 * An asynchronous generator function that fetches logs from the blockchain in a range of blocks.
 *
 * @remarks
 * The function will fetch logs according to the given options.
 * It will iteratively move forward in the block range, yielding fetched logs as they become available.
 * If the function encounters rate limits, it will retry until `maxRetryCount` is reached.
 * If the function encounters a block range that is too large, it will half the block range and retry, until the block range can't be halved anymore.
 *
 * @param {FetchLogsOptions<AbiEvent[]>} options See `FetchLogsOptions`.
 *
 * @yields The result of the fetched logs for each block range in the given range.
 *
 * @throws Will throw an error if the block range can't be reduced any further.
 */
declare function fetchLogs<TAbiEvents extends readonly AbiEvent[]>({ maxBlockRange, maxRetryCount, publicClient, ...getLogsOpts }: FetchLogsOptions<TAbiEvents>): AsyncGenerator<FetchLogsResult<TAbiEvents>>;

type BlockRangeToLogsOptions<TAbiEvents extends readonly AbiEvent[]> = {
    /**
     * [viem `PublicClient`][0] used for fetching logs from the RPC.
     *
     * [0]: https://viem.sh/docs/clients/public.html
     */
    publicClient: PublicClient;
    /**
     * Optional contract address(es) to fetch logs for.
     */
    address?: Address | Address[];
    /**
     * Events to fetch logs for.
     */
    events: TAbiEvents;
    /**
     * Optional maximum block range, if your RPC limits the amount of blocks fetched at a time.
     */
    maxBlockRange?: bigint;
};
type BlockRangeToLogsResult<TAbiEvents extends readonly AbiEvent[]> = OperatorFunction<{
    startBlock: BlockNumber;
    endBlock: BlockNumber;
}, FetchLogsResult<TAbiEvents>>;
/**
 * Takes in an observable of `Observable<{ startBlock: bigint, endBlock: bigint }>`
 * and uses a viem `publicClient` to get logs for the contract `address` and
 * matching `events` and emits the logs as they are fetched.
 *
 * @param {BlockRangeToLogsOptions<AbiEvent[]>} options See `BlockRangeToLogsOptions`.
 * @returns {BlockRangeToLogsResult<AbiEvent[]>} An operator function that transforms a stream of block ranges into a stream of fetched logs.
 */
declare function blockRangeToLogs<TAbiEvents extends readonly AbiEvent[]>({ publicClient, address, events, maxBlockRange, }: BlockRangeToLogsOptions<TAbiEvents>): BlockRangeToLogsResult<TAbiEvents>;

type CreateBlockStreamOptions<TBlockTag extends BlockTag> = {
    publicClient: PublicClient;
    blockTag: TBlockTag;
};
type CreateBlockStreamResult<TBlockTag extends BlockTag> = Observable<Block<bigint, false, TBlockTag>>;
declare function createBlockStream<TBlockTag extends BlockTag>({ publicClient, blockTag, }: CreateBlockStreamOptions<TBlockTag>): CreateBlockStreamResult<TBlockTag>;

type PartialLog = {
    blockNumber: bigint;
    logIndex: number;
};
type GroupLogsByBlockNumberResult<TLog extends PartialLog> = {
    blockNumber: TLog["blockNumber"];
    logs: TLog[];
}[];
/**
 * Groups logs by their block number.
 *
 * @remarks
 * This function takes an array of logs and returns a new array where each item corresponds to a distinct block number.
 * Each item in the output array includes the block number, the block hash, and an array of all logs for that block.
 * Pending logs are filtered out before processing, as they don't have block numbers.
 *
 * @param logs The logs to group by block number.
 * @param toBlock If specified, always include this block number at the end, even if there are no logs.
 *
 * @returns An array of objects where each object represents a distinct block and includes the block number,
 * the block hash, and an array of logs for that block.
 */
declare function groupLogsByBlockNumber<TLog extends PartialLog>(logs: readonly TLog[], toBlock?: BlockNumber): GroupLogsByBlockNumberResult<TLog>;

export { BlockRangeToLogsOptions, BlockRangeToLogsResult, CreateBlockStreamOptions, CreateBlockStreamResult, FetchLogsOptions, FetchLogsResult, GroupLogsByBlockNumberResult, blockRangeToLogs, createBlockStream, fetchLogs, groupLogsByBlockNumber };
