import { Readable } from 'node:stream';
import { APIMethods, APIMethodParams, TelegramInputFile, TelegramInputMediaAnimation, TelegramInputMediaDocument, TelegramInputMediaAudio, TelegramInputMediaPhoto, TelegramInputMediaVideo, TelegramFile } from '@gramio/types';

/** Guard to check is method used for File Uploading */
declare function isMediaUpload<T extends keyof APIMethods>(method: T, params: NonNullable<APIMethodParams<T>>): boolean;
/**
 * Helper to convert JSON to FormData that can accept Telegram Bot API.
 * if File is not top-level property it will be `“attach://<file_attach_name>”`
 *
 * [Documentation](https://core.telegram.org/bots/api#inputfile)
 */
declare function convertJsonToFormData<T extends keyof APIMethods>(method: T, params: NonNullable<APIMethodParams<T>>): Promise<FormData>;
/**
 * Helper to extract files from params and convert them to FormData. (Similar to {@link convertJsonToFormData})
 * if File is not top-level property it will be `“attach://<file_attach_name>”`
 *
 * [Documentation](https://core.telegram.org/bots/api#inputfile)
 */
declare function extractFilesToFormData<T extends keyof APIMethods>(method: T, params: NonNullable<APIMethodParams<T>>): Promise<[FormData | undefined, NonNullable<APIMethodParams<T>>]>;
/** Helper for convert Readable stream to buffer */
declare function convertStreamToBuffer(stream: Readable): Promise<Buffer>;

type Extractor = {
    name: string;
    type: "array" | "union";
    property: string;
};
type MethodsWithMediaUpload = {
    [Method in keyof APIMethods]?: [
        (params: NonNullable<APIMethodParams<Method>>) => boolean,
        Extractor[] | null
    ];
};
/** Guard to check is it {@link Blob} or {@link Promise} */
declare function isBlob(blob?: TelegramInputFile | object | string): boolean;
/**
 * A set of methods with the function of checking whether a {@link File} has been passed in the parameters
 *
 * @codegenerated
 * */
declare const MEDIA_METHODS: MethodsWithMediaUpload;

/**
 *  Class-helper with static methods that represents the content of a media message to be sent.
 *
 * [Documentation](https://gramio.dev/files/media-input.html)
 */
declare class MediaInput {
    /**
     * Represents an animation file (GIF or H.264/MPEG-4 AVC video without sound) to be sent.
     *
     * [Documentation](https://core.telegram.org/bots/api/#inputmediaanimation)
     */
    static animation(media: TelegramInputMediaAnimation["media"], options?: Omit<TelegramInputMediaAnimation, "media" | "type">): TelegramInputMediaAnimation;
    /**
     * Represents a general file to be sent.
     *
     * [Documentation](https://core.telegram.org/bots/api/#inputmediadocument)
     */
    static document(media: TelegramInputMediaDocument["media"], options?: Omit<TelegramInputMediaDocument, "media" | "type">): TelegramInputMediaDocument;
    /**
     * Represents an audio file to be treated as music to be sent.
     *
     * [Documentation](https://core.telegram.org/bots/api/#inputmediaaudio)
     */
    static audio(media: TelegramInputMediaAudio["media"], options?: Omit<TelegramInputMediaAudio, "media" | "type">): TelegramInputMediaAudio;
    /**
     * Represents a photo to be sent.
     *
     * [Documentation](https://core.telegram.org/bots/api/#inputmediaphoto)
     */
    static photo(media: TelegramInputMediaPhoto["media"], options?: Omit<TelegramInputMediaPhoto, "media" | "type">): TelegramInputMediaPhoto;
    /**
     * Represents a video to be sent.
     *
     * [Documentation](https://core.telegram.org/bots/api/#inputmediavideo)
     */
    static video(media: TelegramInputMediaVideo["media"], options?: Omit<TelegramInputMediaVideo, "media" | "type">): TelegramInputMediaVideo;
}

/**
 * Class-helper with static methods for file uploading.
 *
 * [Documentation](https://gramio.dev/files/media-upload.html)
 */
declare class MediaUpload {
    /**
     * Method for uploading Media File by local path.
     */
    static path(path: string, filename?: string): Promise<File>;
    /**
     * Reference a file by its **local path on a self-hosted Bot API server**
     * (`--local` mode) using the `file://` URI scheme. The server reads the file
     * straight from its own disk, so the bytes are **never transferred over HTTP**.
     *
     * This is an **optimization**, not a requirement for large files: a local Bot
     * API server already accepts up to **2 GB** via a normal upload
     * ({@link MediaUpload.path} / {@link MediaUpload.stream}). Use `localPath` only
     * when the file already lives **on the Bot API server's filesystem** (bot
     * co-located, or a shared volume) to skip re-uploading it.
     *
     * @example
     * ```ts
     * // file already on the server's disk → no HTTP upload of the bytes
     * ctx.sendDocument(MediaUpload.localPath("/var/data/big-archive.zip"));
     * ```
     */
    static localPath(path: string): string;
    /**
     * Method for uploading Media File by Readable stream.
     */
    static stream(stream: Readable | ReadableStream, filename?: string): Promise<File>;
    /**
     * Method for uploading Media File by BinaryLike (Buffer or ArrayBuffer and etc).
     */
    static buffer(buffer: Exclude<BufferSource | ArrayBuffer, string>, filename?: string): File;
    /**
     * Method for uploading Media File by URL (also with fetch options).
     */
    static url(url: URL | string, filename?: string, options?: RequestInit): Promise<File>;
    /**
     * Method for uploading Media File by text content.
     */
    static text(text: string, filename?: string): File;
}

/** A resolved file location used by {@link TelegramFileDownload}. */
type FileDownloadSource = {
    type: "url";
    url: string;
} | {
    type: "disk";
    path: string;
} | {
    type: "data";
    data: ArrayBuffer | Uint8Array;
};
/** Lazily resolves the file metadata + where to read it from. */
type FileDownloadResolver = () => Promise<{
    file: TelegramFile;
    source: FileDownloadSource;
}>;
/**
 * Lazy, `Response`-like handle for downloading a Telegram file.
 *
 * It is a `PromiseLike<ArrayBuffer>` — so `await download` still yields the bytes,
 * exactly like before — **plus** convenience readers, mirroring the web `Response`:
 *
 * ```ts
 * const dl = ctx.download();          // nothing fetched yet
 * await dl.bytes();                   // Uint8Array
 * await dl.text();                    // string (utf-8)
 * await dl.json();                    // parsed JSON
 * await dl.blob();                    // Blob
 * await dl.stream();                  // ReadableStream (pipe huge files)
 * await dl.toFile("./photo.jpg");     // save to disk, returns the path
 * await dl.info();                    // getFile metadata (no body read)
 * const buf = await ctx.download();   // ArrayBuffer (back-compatible)
 * ```
 *
 * Like `Response`, the body is **single-use**: read it once, then call
 * `download()` again for another pass. `info()` and `toFile()` (for a local
 * server file) don't consume the body.
 */
declare class TelegramFileDownload implements PromiseLike<ArrayBuffer> {
    #private;
    constructor(resolver: FileDownloadResolver);
    private resolve;
    private response;
    /** The `getFile` metadata (`file_id`, `file_path`, `file_size`, …). Does not read the body. */
    info(): Promise<TelegramFile>;
    /** The whole file as an `ArrayBuffer`. */
    arrayBuffer(): Promise<ArrayBuffer>;
    /** The whole file as a `Uint8Array`. */
    bytes(): Promise<Uint8Array>;
    /** The whole file as a `Blob`. */
    blob(): Promise<Blob>;
    /** The file decoded as UTF-8 text. */
    text(): Promise<string>;
    /** The file parsed as JSON. */
    json<T = unknown>(): Promise<T>;
    /** A web `ReadableStream` of the file — pipe large files without buffering. */
    stream(): Promise<ReadableStream<Uint8Array>>;
    /**
     * A download URL for the file. Does not read the body.
     *
     * ⚠️ **Contains the bot token by default** — the standard Telegram URL is
     * `…/file/bot<token>/<path>`. It is **token-less only when `files.baseURL` is
     * set** (a local server serving the working dir over HTTP), where it becomes
     * `${files.baseURL}/<path>`. Don't hand the default (token-bearing) link to end
     * users; configure `files.baseURL`, or proxy downloads yourself.
     *
     * Throws for a local-server file (`--local`, absolute path) with no
     * `files.baseURL` — there's no HTTP URL, only a path on the server's disk.
     */
    link(): Promise<string>;
    /** Save the file to `path` and return it. Copies on disk when possible (no extra transfer). */
    toFile(path: string): Promise<string>;
    /** `PromiseLike`: `await download` resolves the file bytes (back-compatible). */
    then<TResult1 = ArrayBuffer, TResult2 = never>(onfulfilled?: ((value: ArrayBuffer) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
}
/**
 * Strategy for how {@link downloadFile} obtains file bytes — mainly relevant with a
 * **local Bot API server** (`--local`), where `getFile` returns an absolute path on
 * the server's disk instead of a URL.
 *
 * - `"auto"` *(default)* — absolute `file_path` → `baseURL` rewrite if set, else read
 *   from disk; relative `file_path` → classic download URL.
 * - `"url"` — classic `<baseURL>/file/bot<token>/<path>` download.
 * - `"disk"` — read the absolute `file_path` straight from the local filesystem.
 * - `"rewrite"` — fetch `${files.baseURL}/<relative path>` over HTTP (token-less).
 * - a function — full custom resolution.
 */
type FileSource = "auto" | "url" | "disk" | "rewrite" | ((file: TelegramFile) => Promise<ArrayBuffer> | ArrayBuffer);
/**
 * The minimal `Bot`-shaped object {@link downloadFile} needs. The GramIO `Bot`
 * satisfies it structurally, so you just pass the instance — and a custom
 * "without gramio" wrapper can pass any object of this shape.
 */
interface FileDownloadBot {
    api: {
        getFile(params: {
            file_id: string;
        }): Promise<TelegramFile> | TelegramFile;
    };
    options: {
        token: string;
        api: {
            baseURL: string;
        };
        files?: {
            /** How to fetch bytes. @default "auto" */
            source?: FileSource;
            /** Working directory of the local server — the prefix of the absolute `file_path` it returns. @default "/var/lib/telegram-bot-api" */
            localDir?: string;
            /**
             * Where that working dir is mounted **on the bot's side**, when the bot and
             * server share a volume at a *different* path. For `source: "disk"`, the
             * server path is remapped `localDir` → `mountDir` before reading. Defaults to
             * `localDir` (same path — no remap).
             *
             * @example
             * // server mounts the volume at /var/lib/telegram-bot-api, bot at /data
             * { localDir: "/var/lib/telegram-bot-api", mountDir: "/data" }
             */
            mountDir?: string;
            /** Public base URL the working dir is served at (enables token-less links + `source: "rewrite"`). */
            baseURL?: string;
        };
    };
}
/** Anything {@link downloadFile} can turn into a `file_id`. */
type DownloadFileInput = string | {
    file_id: string;
} | {
    fileId: string;
} | {
    bigSize: {
        fileId: string;
    };
};
/**
 * Download a Telegram file. Returns a {@link TelegramFileDownload} handle
 * (`.bytes()`, `.text()`, `.json()`, `.blob()`, `.stream()`, `.toFile()`,
 * `.link()`, `.info()`; `await` it for an `ArrayBuffer`). Pass `path` to save
 * straight to disk and get the path back.
 *
 * Powers `bot.downloadFile` / `context.download`, and is re-exported from `gramio`
 * so you can call it with a bot instance from anywhere.
 *
 * @example
 * ```ts
 * import { downloadFile } from "gramio";
 *
 * const dl = downloadFile(bot, fileId);
 * await dl.toFile("./photo.jpg");
 * const text = await downloadFile(bot, fileId).text();
 * ```
 */
declare function downloadFile(bot: FileDownloadBot, attachment: DownloadFileInput): TelegramFileDownload;
declare function downloadFile(bot: FileDownloadBot, attachment: DownloadFileInput, path: string): Promise<string>;

export { MEDIA_METHODS, MediaInput, MediaUpload, TelegramFileDownload, convertJsonToFormData, convertStreamToBuffer, downloadFile, extractFilesToFormData, isBlob, isMediaUpload };
export type { DownloadFileInput, FileDownloadBot, FileDownloadResolver, FileDownloadSource, FileSource };
