"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TelegramBotPolling = void 0;
const debug_js_1 = __importDefault(require("./internal/debug.cjs"));
const errors_js_1 = require("./errors.cjs");
const debug = (0, debug_js_1.default)("node-telegram-bot-api:polling");
const ANOTHER_WEB_HOOK_USED = 409;
class TelegramBotPolling {
    bot;
    interval;
    params;
    _abort = false;
    _abortController;
    _activeRequest = null;
    _pollingTimeout = null;
    _running = false;
    constructor(bot, options = {}) {
        this.bot = bot;
        this.interval = typeof options.interval === "number" ? options.interval : 300;
        const params = options.params ?? {};
        this.params = {
            ...params,
            offset: typeof params.offset === "number" ? params.offset : 0,
            timeout: typeof params.timeout === "number" ? params.timeout : 10,
        };
        if (typeof options.timeout === "number") {
            this.params.timeout = options.timeout;
        }
    }
    /**
     * Start polling. If polling is already running, the call resolves immediately
     * unless `restart: true` is passed (in which case the previous loop is cancelled
     * before a fresh one is started).
     */
    async start(options = {}) {
        if (this._running) {
            if (!options.restart)
                return;
            await this.stop({ cancel: true, reason: "Polling restart" });
        }
        this._running = true;
        this._abort = false;
        void this._loop();
    }
    /**
     * Stop polling. Resolves once the current `getUpdates` call has completed.
     */
    async stop(options = {}) {
        if (!this._running)
            return;
        this._running = false;
        if (this._pollingTimeout) {
            clearTimeout(this._pollingTimeout);
            this._pollingTimeout = null;
        }
        if (options.cancel && this._abortController) {
            this._abortController.abort(options.reason ?? "Polling stop");
        }
        this._abort = true;
        if (this._activeRequest) {
            try {
                await this._activeRequest;
            }
            catch {
                /* swallow — caller has already been notified */
            }
        }
    }
    isPolling() {
        return this._running;
    }
    _emitError(err) {
        if (!this.bot.listeners("polling_error").length) {
            // Fallback: log to stderr.
            // eslint-disable-next-line no-console
            console.error(`${new Date().toISOString()} error: [polling_error] %j`, err);
            return;
        }
        this.bot.emit("polling_error", err);
    }
    _scheduleNext() {
        if (!this._running || this._abort) {
            debug("Polling aborted");
            return;
        }
        debug("setTimeout for %s milliseconds", this.interval);
        this._pollingTimeout = setTimeout(() => void this._loop(), this.interval);
    }
    async _loop() {
        const request = this._poll();
        this._activeRequest = request;
        try {
            await request;
        }
        finally {
            this._activeRequest = null;
            this._scheduleNext();
        }
    }
    async _poll() {
        try {
            const updates = await this._getUpdates();
            debug("polling data %j", updates);
            for (const update of updates) {
                this.params.offset = update.update_id + 1;
                debug("updated offset: %s", this.params.offset);
                try {
                    this.bot.processUpdate(update);
                }
                catch (err) {
                    err._processing = true;
                    throw err;
                }
            }
        }
        catch (err) {
            const flagged = err;
            debug("polling error: %s", err.message);
            if (!flagged._processing) {
                this._emitError(err);
                return;
            }
            delete flagged._processing;
            // Update-processing failure handling — see the original library's discussion at
            // https://github.com/yagop/node-telegram-bot-api/issues/36#issuecomment-268532067
            try {
                await this.bot.getUpdates({
                    offset: this.params.offset,
                    limit: 1,
                    timeout: 0,
                });
                this._emitError(err);
            }
            catch (requestErr) {
                // eslint-disable-next-line no-console
                console.error(`${new Date().toISOString()} error: Internal handling of The Offset Infinite Loop failed`, requestErr);
                this.bot.emit("error", new errors_js_1.FatalError(err));
            }
        }
    }
    async _getUpdates() {
        debug("polling with options: %j", this.params);
        try {
            return await this.bot.getUpdates(this.params);
        }
        catch (err) {
            const status = err.response?.status;
            if (status === ANOTHER_WEB_HOOK_USED) {
                debug("unsetting webhook because polling is in use");
                await this.bot.deleteWebHook();
                return this.bot.getUpdates(this.params);
            }
            throw err;
        }
    }
}
exports.TelegramBotPolling = TelegramBotPolling;
//# sourceMappingURL=polling.cjs.map