import * as undici_types from 'undici-types';
import EventEmitter from 'eventemitter3';

/**
 * Represents a bucket for handling ratelimiting.
 */
declare class SequentialBucket {
    #private;
    /** The maximum requests that can be made by the bucket. */
    limit: number;
    /** The remaining requests that can be made by the bucket. */
    remaining: number;
    /** The timestamp of the next reset. */
    reset: number;
    /**
     * Represents a bucket for handling ratelimiting.
     * @arg rest Represents the RequestHandler.
     * @arg hash The hash used to identify the bucket.
     * @arg majorParameter The major parameter of the requests.
     */
    constructor(rest: RequestHandler, hash: string, majorParameter: string);
    /**
     * The identifier of the bucket.
     * @readonly
     */
    get id(): string;
    /**
     * Whether the bucket is no longer in use.
     * @readonly
     */
    get inactive(): boolean;
    /**
     * Whether the bucket is currently limited.
     * @readonly
     */
    get limited(): boolean;
    /**
     * Enqueue a request to be sent.
     * @arg request The request to enqueue.
     * @arg next Whether to insert the request at the start of the queue.
     * @returns Resolves with the returned JSON data.
     */
    add<T = unknown>(request: Request, next?: boolean): Promise<T>;
}

/** The options for a {@link RequestHandler}. */
interface RESTOptions {
    /** The dispatcher to use for undici. */
    dispatcher?: undici_types.Dispatcher;
    /** The base URL to use for API requests. */
    baseURL?: string;
    /** A number of milliseconds to offset the ratelimit timing calculations by. */
    ratelimiterOffset?: number;
    /** A number of milliseconds before requests are considered timed out. */
    requestTimeout?: number;
    /** The amount of times it will retry to send the request. */
    retryLimit?: number;
}
interface HashData {
    value: string;
    lastAccess: number;
}
/** The options for a {@link Request}. */
interface RequestOptions {
    /** Whether to add the "Authorization" header. */
    auth?: boolean;
    /** The data to be set for the request body. */
    body?: Record<string, any>;
    /** The headers to attach to the request. */
    headers?: Record<string, string>;
    /** The files to attach to the request body. */
    files?: FileContent[];
    /** An object of query keys and their values. */
    query?: Record<string, any>;
    /** The reason to display in the audit log. */
    reason?: string;
}
/** The contents of a file. */
interface FileContent {
    file: any;
    name: string;
}
/**
 * Represents a class to handle requests.
 */
declare class RequestHandler {
    #private;
    /** The manager that instansiated this handler. */
    manager?: EmojiManager;
    /** A map with SequentialBuckets. */
    buckets: Map<string, SequentialBucket>;
    /** Whether we are currently globally limited. */
    globalBlock: boolean;
    /** The timestamp of the next reset. */
    globalReset: number;
    /** A promise that will resolve as soon we are no longer limited. */
    globalTimeout?: Promise<void>;
    /** A map with bucket hash data. */
    hashes: Map<string, HashData>;
    /** Options for the RequestHandler. */
    options: RESTOptions;
    /**
     * Represents a class to handle requests.
     * @arg options Options for the RequestHandler.
     */
    constructor(manager?: EmojiManager, options?: RESTOptions & {
        token?: string;
    });
    /**
     * Whether we are currently globally limited.
     * @readonly
     */
    get limited(): boolean;
    /**
     * Makes a request to the API.
     * @arg method An uppercase HTTP method.
     * @arg path The endpoint to make the request to.
     * @arg options Data regarding the request.
     * @returns Resolves with the returned JSON data.
     */
    request<T = unknown>(method: string, path: string, options?: RequestOptions): Promise<T>;
}

/**
 * Represents the request.
 */
declare class Request {
    #private;
    /** The data to be set for the request body. */
    data?: FormData | string;
    /** The RequestHandler. */
    handler: RequestHandler;
    /**
     * The headers to attach to the request.
     * @type {Object}
     */
    headers: Record<string, string>;
    /** The major parameter of the request. */
    majorParameter: string;
    /** An uppercase HTTP method. */
    method: string;
    /** Data regarding the request. */
    options: RequestOptions;
    /** The endpoint to make the request to. */
    path: string;
    /** The route to make the request to. */
    route: string;
    /** The URL to make the request to. */
    url: URL;
    /**
     * Represents the request.
     * @arg handler Represents the RequestHandler.
     * @arg method An uppercase HTTP method.
     * @arg path The endpoint to make the request to.
     * @arg options Data regarding the request.
     */
    constructor(handler: RequestHandler, method: string, path: string, options: RequestOptions);
    /**
     * The identifier of the request.
     * @readonly
     */
    get id(): string;
    /**
     * Sends the request to Discord.
     * @returns The response.
     */
    send(): Promise<Response>;
    /**
     * Attach data to the request.
     * @arg body Optional data to attach to the request.
     * @arg files Optional files to attach to the request.
     */
    setBody(body?: Record<string, any>, files?: FileContent[]): Request;
}

/** The version of this package. */
declare const VERSION = "0.1.2";
/** The API version this package supports. */
declare const API_VERSION = 10;
/** The base API URL to use in requests. */
declare const API_BASE_URL: string;
/** The URL for Discord's CDN. */
declare const CDN_URL = "https://cdn.discordapp.com";
/**
 * A user's avatar decoration data.
 * @see https://discord.com/developers/docs/resources/user#avatar-decoration-data-object
 */
interface AvatarDecorationData {
    /** The avatar decoration hash */
    asset: string;
    /** The id of the avatar decoration's SKU */
    sku_id: string;
}
/**
 * A user object.
 * @see https://discord.com/developers/docs/resources/user#user-object
 */
interface User {
    /** The user's id */
    id: string;
    /** The user's username, not unique across the platform */
    username: string;
    /** The user's avatar hash */
    avatar: string | null;
    /** The user's Discord-tag */
    discriminator: string;
    /** The public flags on a user's account. */
    public_flags: number;
    /** The flags on a user's account. */
    flags: number;
    /** Whether the user belongs to an OAuth2 application */
    bot?: boolean;
    /** The user's banner hash */
    banner?: string | null;
    /** The user's banner color encoded as an integer representation of hexadecimal color code */
    accent_color?: number | null;
    /** The user's display name, if it is set. For bots, this is the application name */
    global_name: string | null;
    /** The data for the user's avatar decoration */
    avatar_decoration_data?: AvatarDecorationData | null;
}
/**
 * A partial emoji object, usable with buttons and selects.
 * @see https://discord.com/developers/docs/resources/emoji#emoji-object-emoji-structure
 */
interface PartialEmoji {
    /** Emoji id */
    id: string;
    /** Emoji name */
    name: string;
    /** Whether this emoji is animated */
    animated: boolean;
}
/**
 * An emoji object.
 * @see https://discord.com/developers/docs/resources/emoji#emoji-object-emoji-structure
 */
interface Emoji extends PartialEmoji {
    user: User;
    roles: string[];
    require_colons: boolean;
    managed: boolean;
    available: boolean;
}
/**
 * A request object for tracking requests coming from the {@link EmojiManager}.
 */
interface RawRequest {
    auth: boolean;
    body: Record<string, any> | undefined;
    files: FileContent[] | undefined;
    latency: number;
    url: URL;
    method: string;
    response: Response;
    request: Request;
}

/** The options for the {@link EmojiManager}. */
interface EmojiManagerOptions {
    /** TThe bot/client token of the Discord application. */
    token: string;
    /**
     * The application ID for use in the manager.
     * If not defined, the manager will fetch the application ID before other requests are made.
     */
    applicationId?: string;
    /** The options passed to the request handler. */
    rest?: RESTOptions;
}
/**
 * The events typings for the {@link EmojiManager}.
 * @private
 */
interface EmojiManagerEvents {
    rawREST: (request: RawRequest) => void;
    warn: (warning: string) => void;
    debug: (message: string) => void;
    error: (err: Error) => void;
}
/** The options for {@link EmojiManager.loadFromFolder} */
interface LoadFromFolderOptions {
    /** Whether to recursively get files in the folder */
    recursive?: boolean;
}
/**
 * A manager for managing an emoji collection.
 */
declare class EmojiManager<Key extends string = string> extends EventEmitter<EmojiManagerEvents> {
    #private;
    /** The application ID of the manager. */
    applicationId?: string;
    /** The request handler for the manager. */
    readonly requestHandler: RequestHandler;
    /** Emojis matched by their key. */
    readonly emojis: Map<Key, Emoji>;
    /** @param opts The options for the manager */
    constructor(opts: EmojiManagerOptions);
    /**
     * Get an emoji object
     * @param key The emoji key to get
     * @returns The emoji object
     */
    get(key: Key): Emoji | null;
    /**
     * Get a partial emoji object for use in buttons/selects.
     * @param key The emoji key to get
     * @returns The partial emoji object
     */
    getPartial(key: Key): PartialEmoji | null;
    /**
     * Get an emoji as a formatted markdown element
     * @param key The emoji key to get
     * @returns The formatted markdown representation of the emoji
     */
    getMarkdown(key: Key): string | null;
    /**
     * Load emojis into the manager. The values can either be a data image uri (starting with `data:`), URLs (starting with `http(s):`), or file paths.
     * @param emojis The emojis to load into the manager
     */
    load(emojis: Record<string, string>): void;
    /**
     * Load image files from a folder.
     * @param folderPath The folder to load emojis from
     * @param options Options for the function
     */
    loadFromFolder(folderPath: string, options?: LoadFromFolderOptions): Promise<void>;
    /**
     * Syncs the local emojis to the application.
     */
    sync(): Promise<void>;
    /**
     * Load an array of emojis that were previously fetched from the Discord API into the manager.
     * @param emojis The emojis from the Discord API to load
     */
    loadFromDiscord(emojis: Emoji[]): void;
}

/**
 * Get the paths of files in a folder
 * @param folderPath The folder to get files from
 * @param recursive Whether to get files recursively
 * @returns The paths of the inside the folder
 */
declare function getFiles(folderPath: string, recursive?: boolean): Promise<string[]>;
/**
 * Calculates the timestamp in milliseconds associated with a Discord ID/snowflake
 * @param id The ID of a structure
 */
declare function getCreatedAt(id: string): number;
/**
 * Gets the number of milliseconds since epoch represented by an ID/snowflake
 * @param id The ID of a structure
 */
declare function getDiscordEpoch(id: string): number;
/**
 * Converts an emoji to a formatted markdown string
 * @param emoji The emoji to convert to a markdown format
 * @returns The formatted markdown string
 */
declare function toMarkdown(emoji: Omit<PartialEmoji, 'animated'> & {
    animated?: boolean;
}): string;
/**
 * Converts data to a data URI
 * @param data The data to convert
 * @param mimeType The MIME type of the data
 * @returns The data URI string
 */
declare function toDataUri(data: Buffer | ArrayBuffer, mimeType: string): string;
/**
 * Converts a file extension to a MIME type
 * @param extension The file extension to convert
 * @returns The corresponding MIME type or null if unsupported
 */
declare function extensionToMimeType(extension: string): string | null;

/** An HTTP error from a request. */
declare class DiscordHTTPError extends Error {
    /** The client request of the error. */
    readonly req: Request;
    /** The response from the server. */
    readonly res: Response;
    /** The response class from a {@link Server}. */
    readonly response: any;
    /** The status code from the response. */
    readonly code: number;
    /** The error stack. */
    readonly stack: string;
    /**
     * @param req A client request
     * @param res A response
     * @param stack The error stack
     */
    constructor(req: Request, res: Response, stack: string);
    get headers(): Headers;
    get name(): string;
}

/** An Discord error from a request. */
declare class DiscordRESTError extends Error {
    /** The client request of the error. */
    readonly req: Request;
    /** The response from the server. */
    readonly res: Response;
    /** The response class from a {@link Server}. */
    readonly response: any;
    /** The error code from the response. */
    readonly code: number;
    /** The message of the error. */
    readonly message: string;
    /** The error stack. */
    readonly stack: string;
    /**
     * @param req A client request
     * @param res An incoming message from the server
     * @param response A response's body
     * @param stack The error stack
     */
    constructor(req: Request, res: Response, response: any, stack: string);
    get name(): string;
    private flattenErrors;
}

export { API_BASE_URL, API_VERSION, type AvatarDecorationData, CDN_URL, DiscordHTTPError, DiscordRESTError, type Emoji, EmojiManager, type EmojiManagerOptions, type LoadFromFolderOptions, type PartialEmoji, type RawRequest, type User, VERSION, extensionToMimeType, getCreatedAt, getDiscordEpoch, getFiles, toDataUri, toMarkdown };
