import { Logger } from 'log4js';
import { P2P } from '@shardeum-foundation/lib-types';
import { Result } from 'neverthrow';
import { ActiveNode } from '@shardeum-foundation/lib-types/build/src/p2p/SyncTypes';
export type QueryFunction<Node, Response> = (node: Node) => PromiseLike<Response>;
export type VerifyFunction<Result> = (result: Result) => boolean;
export type EqualityFunction<Value> = (val1: Value, val2: Value) => boolean;
export type CompareFunction<Result> = (result: Result) => Comparison;
export declare enum Comparison {
    BETTER = 0,
    EQUAL = 1,
    WORSE = 2,
    ABORT = 3
}
export interface CompareQueryError<Node> {
    node: Node;
    error: string;
}
export type CompareFunctionResult<Node> = Array<CompareQueryError<Node>>;
export interface SequentialQueryError<Node> {
    node: Node;
    error: Error;
    response?: unknown;
}
export interface SequentialQueryResult<Node> {
    result: unknown;
    errors: Array<SequentialQueryError<Node>>;
}
export type SeedNodesList = {
    nodeList: P2P.P2PTypes.Node[];
    joinRequest: P2P.ArchiversTypes.Request | undefined;
    restartCycleRecord: P2P.ArchiversTypes.RestartCycleRecord | undefined;
    dataRequestCycle: unknown;
    dataRequestStateMetaData: unknown;
};
export declare function compareQuery<Node = unknown, Response = unknown>(nodes: Node[], queryFn: QueryFunction<Node, Response>, compareFn: CompareFunction<Response>, matches: number): Promise<CompareFunctionResult<Node>>;
/**
 * TODO PERF replace shuffle with fastRandomIterator (currently sequentialQuery is unused)
 * @param nodes
 * @param queryFn
 * @param verifyFn
 */
export declare function sequentialQuery<Node = unknown, Response = unknown>(nodes: Node[], queryFn: QueryFunction<Node, Response>, verifyFn?: VerifyFunction<Response>): Promise<SequentialQueryResult<Node>>;
export type RobustQueryResult<N, R> = {
    topResult: R;
    winningNodes: N[];
    isRobustResult: boolean;
};
/**
 * [TODO] robustQuery should handle being given an enourmous node list (Dont copy and shuffle it)
 *
 * TODO replace console.log with a specific log funtion.
 *
 * Note -
 * robustQuery should NOT be given a node list that includes yourself (Use NodeList.activeOthersByIdOrder).
 * OR
 * the queryFunction can return null if the node being queried is Self.id
 *
 * @param nodes
 * @param queryFn
 * @param equalityFn
 * @param redundancy
 * @param shuffleNodes
 * @param strictRedundancy
 * @param extraDebugging
 */
export declare function robustQuery<Node = unknown, Response = unknown>(nodes: Node[], queryFn: QueryFunction<Node, Response>, equalityFn?: EqualityFunction<Response>, redundancy?: number, shuffleNodes?: boolean, strictRedundancy?: boolean, extraDebugging?: boolean, note?: string, maxRetry?: number): Promise<RobustQueryResult<Node, Response>>;
/**
 * Attempts to execute a given asynchronous function up to a certain number of retries upon failure.
 *
 * @template T The type of the resolved value of the input function.
 * @param {() => Promise<T>} fn - The asynchronous function to execute. This function should return a Promise that resolves to a value of type `T`.
 * @param {AttemptOptions} options - Optional. Options passed to change the behavior of this function. See the `AttemptOptions` interface in this same file for details.
 * @returns {Promise<T>} A Promise that resolves to the return value of the input function, if successful.
 * @throws Will throw an error if the function fails all attempts. The error will be the last error thrown by the input function.
 */
export declare function attempt<T>(fn: () => Promise<T>, options?: AttemptOptions): Promise<T>;
/** A little interface to represent the options you can pass to the `attempt` function. */
export interface AttemptOptions {
    /** The maximum number of attempts to execute the function. */
    maxRetries?: number;
    /** The delay between attempts, in milliseconds. */
    delay?: number;
    /** A log prefix to prepend to error logs on each failure. */
    logPrefix?: string;
    /** The logger to write to on failures. */
    logger?: Logger;
    /** optional timeout default 1000ms */
    timeout?: number;
}
export declare function generateUUID(): string;
export declare function getOurNodeIndex(): number | null;
export declare const getOurNodeIndexFromSyncingList: () => number | null;
export declare function getRandomAvailableArchiver(): P2P.SyncTypes.ActiveNode;
export declare function getActiveNodesFromArchiver(archiver: ActiveNode): Promise<Result<P2P.P2PTypes.SignedObject<SeedNodesList>, Error>>;
/**
 * Returns true if a node was recently rotate in or
 * will be rotated out soon
 * @param nodeId
 * @returns
 */
export declare function isNodeInRotationBounds(nodeId: string): boolean;
