import { ChalkInstance } from "chalk";
import type { Stats } from "fs";
import { Result } from "./Result.js";
import { File, Searchee } from "./searchee.js";
export type Awaitable<T> = T | Promise<T>;
type Truthy<T> = T extends false | "" | 0 | null | undefined ? never : T;
export type WithRequired<T, K extends keyof T> = T & {
    [P in K]-?: T[P];
};
export type WithUndefined<T, K extends keyof T> = Omit<T, K> & {
    [P in K]: undefined;
};
export declare function isTruthy<T>(value: T): value is Truthy<T>;
export declare function exists(srcPath: string): Promise<boolean>;
export declare function notExists(srcPath: string): Promise<boolean>;
export type DirVerificationFailureReason = "missing" | "not-directory" | "unreadable" | "unwritable";
export type DirVerificationResult = {
    ok: true;
    stats: Stats;
} | {
    ok: false;
    reason: DirVerificationFailureReason;
    error?: unknown;
};
export declare function verifyDir(srcDir: string, testSrcName: string, permissions: number): Promise<DirVerificationResult>;
export declare function isChildPath(childPath: string, parentDirs: string[]): boolean;
export declare function countDirEntriesRec(dirs: string[], maxDataDepth: number): Promise<number>;
export declare function hasExt(files: File[], exts: string[]): boolean;
export declare function stripExtension(filename: string): string;
export declare function filesWithExt(files: File[], exts: string[]): File[];
export declare function findAFileWithExt(dir: string, exts: string[]): Promise<string | null>;
export declare function nMsAgo(n: number): number;
export declare function wait(n: number): Promise<void>;
/**
 * Yield control to the event loop allowing all pending tasks to be processed
 * regardless of the current phase.
 * @param n Optional number of milliseconds to wait before yielding.
 */
export declare function yieldToEventLoop(n?: number): Promise<void>;
export declare function time<R>(cb: () => Promise<R>, times: number[]): Promise<R>;
export declare function humanReadableDate(timestamp: number): string;
export declare function getLogString(searchee: Searchee, color?: ChalkInstance): string;
export declare function formatAsList(strings: string[], options: {
    sort: boolean;
    style?: Intl.ListFormatStyle;
    type?: Intl.ListFormatType;
}): string;
/**
 * This cannot be done at the log level because of too many false positives.
 * The caller will need to extract the infoHash from their specific syntax.
 * @param infoHash The infoHash to sanitize
 */
export declare function sanitizeInfoHash(infoHash: string): string;
export declare function areMediaTitlesSimilar(a: string, b: string): boolean;
export declare function cleanseSeparators(str: string): string;
export declare function cleanTitle(title: string): string;
export declare function cleanBookAndAudioTitle(title: string): string;
export declare function reformatTitleForSearching(name: string): string;
export declare function createKeyTitle(title: string): string | null;
export declare function isBadTitle(title: string): boolean;
/**
 * Generates possible anime search queries from a given name.
 * Only use if getMediaType returns anime as it's conditional on a few factors.
 * @param stem The name without extension to generate queries from.
 * @returns An array of possible search queries.
 */
export declare function getAnimeQueries(stem: string): string[];
/**
 * Generates possible video search queries from a given name.
 * Only use if getMediaType returns video as it's conditional on a few factors.
 * @param stem The name without extension to generate queries from.
 * @returns An array of possible search queries.
 */
export declare function getVideoQueries(stem: string): string[];
export declare function stripMetaFromName(name: string): string;
export declare function sanitizeUrl(url: string | URL): string;
export declare function getApikey(url: string): string | null;
export declare function extractCredentialsFromUrl(url: string, basePath?: string): Result<{
    username: string;
    password: string;
    href: string;
}, "invalid URL">;
export declare const tap: (fn: any) => (value: any) => any;
export declare function fallback<T>(...args: T[]): T | undefined;
export declare function findFallback<T, U>(arr: T[], items: U[], cb: (e: T, item: U) => boolean): T | undefined;
export declare function inBatches<T>(items: T[], cb: (batch: T[]) => Promise<void>, options?: {
    batchSize: number;
}): Promise<void>;
export declare function fromBatches<T, R>(items: T[], cb: (batch: T[]) => Promise<R[]>, options?: {
    batchSize: number;
}): Promise<R[]>;
/**
 * Makes comparators for `Array.prototype.sort`.
 * Second getter will be used if the first is a tie, etc.
 * Booleans are treated as 0 and 1,
 * Ascending by default, use - or ! for descending.
 * @param getters
 */
export declare function comparing<T>(...getters: ((e: T) => number | boolean)[]): (a: T, b: T) => 0 | 1 | -1;
export declare function filterAsync<T>(arr: T[], predicate: (e: T) => Promise<boolean>): Promise<T[]>;
/**
 * Filters an array asynchronously in batches, yielding to the event loop
 * between batches to avoid blocking the event loop for too long.
 * @param arr The array to filter.
 * @param predicate The asynchronous predicate function to test each element.
 * @param options.batchSize The size of each batch to process.
 * @returns A promise that resolves to an array of elements that satisfy the predicate.
 */
export declare function filterAsyncYield<T>(arr: T[], predicate: (e: T) => Promise<boolean>, options?: {
    batchSize: number;
}): Promise<T[]>;
export declare function mapAsync<T, R>(arr: T[], cb: (e: T) => Promise<R>): Promise<R[]>;
export declare function flatMapAsync<T, R>(arr: T[], cb: (e: T) => Promise<R[]>): Promise<R[]>;
export declare function reduceAsync<T, R>(arr: T[], cb: (acc: R, cur: T, index: number, arr: T[]) => Promise<R>, initialValue: R): Promise<R>;
export declare function findAsync<T>(it: Iterable<T>, cb: (e: T) => Promise<boolean>): Promise<T | undefined>;
export declare function someAsync<T>(it: Iterable<T>, cb: (e: T) => Promise<boolean>): Promise<boolean>;
export declare function everyAsync<T>(it: Iterable<T>, cb: (e: T) => Promise<boolean>): Promise<boolean>;
/**
 * Given multiple async iterables, this function will merge/interleave
 * them all into one iterable, yielding on a first-come, first-serve basis.
 * https://stackoverflow.com/questions/50585456/how-can-i-interleave-merge-async-iterables
 */
export declare function combineAsyncIterables<T>(asyncIterables: AsyncIterable<T>[]): AsyncGenerator<T>;
export declare function capitalizeFirstLetter(string: string): string;
/**
 * Replaces the last occurrence of a GLOBAL regex match in a string
 * @param str The string to replace the last occurrence in
 * @param globalRegExp The regex to match (must be global)
 * @param newStr The string to replace the last occurrence with
 */
export declare function replaceLastOccurrence(str: string, globalRegExp: RegExp, newStr: string): string;
export declare function escapeUnescapedQuotesInJsonValues(jsonStr: string): string;
export declare function extractInt(str: string): number;
export declare function getPathParts(pathStr: string, dirnameFunc?: (path: string) => string): string[];
export declare enum Mutex {
    INDEX_TORRENTS_AND_DATA_DIRS = "INDEX_TORRENTS_AND_DATA_DIRS",
    CHECK_JOBS = "CHECK_JOBS",
    CREATE_ALL_SEARCHEES = "CREATE_ALL_SEARCHEES",
    GUID_INFO_HASH_MAP = "GUID_INFO_HASH_MAP",
    CLIENT_INJECTION = "CLIENT_INJECTION"
}
/**
 * Executes a callback function within a mutex for the given name.
 * @param name The name of the mutex to create/use.
 * @param options.useQueue If false, concurrent calls will share the pending result.
 * @param cb The callback to execute.
 * @returns The result of the callback.
 */
export declare function withMutex<T>(name: Mutex, options: {
    useQueue: boolean;
}, cb: () => Promise<T>): Promise<T>;
/**
 * An async safe semaphore implementation that preserves FIFO order.
 * It uses an id for release to allow multiple releases (e.g try/finally with early releases).
 * @param options.permits The number of concurrent permits.
 * @param options.lifetimeMs Maximum lifetime of an acquire before automatic release.
 */
export declare class AsyncSemaphore {
    private permits;
    private lifetimeMs?;
    private acquired;
    private timers;
    private waiting;
    private counter;
    private getNextId;
    constructor(options: {
        permits: number;
        lifetimeMs?: number;
    });
    acquire(): Promise<number>;
    release(id: number): void;
}
export {};
