"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
    for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.InputFile = exports.toRaw = exports.baseFetchConfig = exports.itrToStream = exports.debug = void 0;
const http_1 = require("http");
const https_1 = require("https");
const node_fetch_1 = require("node-fetch");
const path_1 = require("path");
const stream_1 = require("stream");
const url_1 = require("url");
const fs_1 = require("fs");
// === Export all API types
__exportStar(require("@grammyjs/types"), exports);
// === Export debug
const debug_1 = require("debug");
Object.defineProperty(exports, "debug", { enumerable: true, get: function () { return debug_1.debug; } });
const debug = (0, debug_1.debug)("grammy:warn");
// === Export system-specific operations
// Turn an AsyncIterable<Uint8Array> into a stream
const itrToStream = (itr) => stream_1.Readable.from(itr, { objectMode: false });
exports.itrToStream = itrToStream;
// === Base configuration for `fetch` calls
function baseFetchConfig(apiRoot) {
    if (apiRoot.startsWith("https:")) {
        return { compress: true, agent: new https_1.Agent({ keepAlive: true }) };
    }
    else if (apiRoot.startsWith("http:")) {
        return { agent: new http_1.Agent({ keepAlive: true }) };
    }
    else
        return {};
}
exports.baseFetchConfig = baseFetchConfig;
// === InputFile handling and File augmenting
// Accessor for file data in `InputFile` instances
exports.toRaw = Symbol("InputFile data");
/**
 * An `InputFile` wraps a number of different sources for [sending
 * files](https://grammy.dev/guide/files.html#uploading-your-own-file).
 *
 * It corresponds to the `InputFile` type in the [Telegram Bot API
 * Reference](https://core.telegram.org/bots/api#inputfile).
 */
class InputFile {
    /**
     * Constructs an `InputFile` that can be used in the API to send files.
     *
     * @param file A path to a local file or a `Buffer` or a `fs.ReadStream` that specifies the file data
     * @param filename Optional name of the file
     */
    constructor(file, filename) {
        this.consumed = false;
        this.fileData = file;
        filename !== null && filename !== void 0 ? filename : (filename = this.guessFilename(file));
        this.filename = filename;
        if (typeof file === "string" &&
            (file.startsWith("http:") || file.startsWith("https:"))) {
            debug(`InputFile received the local file path '${file}' that looks like a URL. Is this a mistake?`);
        }
    }
    guessFilename(file) {
        if (typeof file === "string")
            return (0, path_1.basename)(file);
        if (typeof file !== "object")
            return undefined;
        if ("url" in file)
            return (0, path_1.basename)(file.url);
        if (!(file instanceof url_1.URL))
            return undefined;
        return (0, path_1.basename)(file.pathname) || (0, path_1.basename)(file.hostname);
    }
    [exports.toRaw]() {
        if (this.consumed) {
            throw new Error("Cannot reuse InputFile data source!");
        }
        const data = this.fileData;
        // Handle local files
        if (typeof data === "string")
            return (0, fs_1.createReadStream)(data);
        // Handle URLs and URLLike objects
        if (data instanceof url_1.URL) {
            return data.protocol === "file" // node-fetch does not support file URLs
                ? (0, fs_1.createReadStream)(data.pathname)
                : fetchFile(data);
        }
        if ("url" in data)
            return fetchFile(data.url);
        // Mark streams and iterators as consumed
        if (!(data instanceof Uint8Array))
            this.consumed = true;
        // Return buffers and byte streams as-is
        return data;
    }
}
exports.InputFile = InputFile;
async function* fetchFile(url) {
    const { body } = await (0, node_fetch_1.default)(url);
    for await (const chunk of body) {
        if (typeof chunk === "string") {
            throw new Error(`Could not transfer file, received string data instead of bytes from '${url}'`);
        }
        yield chunk;
    }
}
