import { Conversation } from "./conversation.js";
import { type ApiClientOptions, Context, type Middleware, type MiddlewareFn, type Update, type UserFromGetMe } from "./deps.node.js";
import { type ReplayState } from "./engine.js";
import { type ConversationStorage } from "./storage.js";
/**
 * Base data that is needed to enter or resume a conversation function. Contains
 * a subset of properties from the current context object of the outside
 * middleware tree.
 *
 * The contained update is supplied as the new update for the most recent wait
 * call.
 */
export interface ContextBaseData {
    /** The new update to supply to the conversation */
    update: Update;
    /** Basic information used to construct `Api` instances */
    api: ApiBaseData;
    /** Information about the bot itself. */
    me: UserFromGetMe;
}
/**
 * Base data that is needed to construct new `Api` instances from scratch.
 * Contains a subset of properties from `ctx.api` from the outside middleware
 * tree.
 */
export interface ApiBaseData {
    /** The bot's token obtained from [@BotFather](https://t.me/BotFather) */
    token: string;
    /** Optional confiugration options for the underlying API client */
    options?: ApiClientOptions;
}
/**
 * Optional configuration options for the conversations plugin.
 *
 * Note that this configuration object takes two different types of custom
 * context types. The first type parameter should corresopnd with the context
 * type of the outside middleware tree. It is used to connect to external
 * storages.
 *
 * The second type parameter should correspond with the custom context type used
 * inside all conversations. It is used if you define a list of default plugins
 * to be installed in every conversation you use. If the list of plugins differs
 * between conversations, you may want to use different context types for them.
 * In that case, you should use a context type for only those plugins that are
 * shared between all conversations, or avoid a list of default plugins
 * entirely.
 *
 * @typeParam OC Custom context type of the outside middleware
 * @typeParam C Custom context type used inside conversations
 */
export interface ConversationOptions<OC extends Context, C extends Context> {
    /**
     * Defines how to persist and version conversation data in between replays.
     * Most likely, you will want to use this option, as your data is lost
     * otherwise.
     *
     * Data can be stored based on a context object, or based on a key derived
     * from the context object. See {@link ConversationStorage} for more
     * information.
     *
     * Defaults to an in-memory implementation of the storage. This means that
     * all conversations will be left when your process terminates.
     *
     * Defaults to storing data per chat based on `ctx.chatId`.
     */
    storage?: ConversationStorage<OC, ConversationData>;
    /**
     * List of default plugins to install for all conversations.
     *
     * Each conversation will have these plugins installed first. In addition,
     * each conversation will have the plugins installed that you specify
     * explicitly when using {@link enterConversation}.
     */
    plugins?: Middleware<C>[];
    /**
     * Called when a conversation is entered via `ctx.conversation.enter`.
     *
     * @param id The identifer of the conversation that was entered
     * @param ctx The current context object
     */
    onEnter?(id: string, ctx: OC): unknown | Promise<unknown>;
    /**
     * Called when a conversation is left via `ctx.conversation.exit` or
     * `conversation.halt`.
     *
     * Note that this callback is not called when a conversation exists normally
     * by returning or by throwing an error. If you wish to execute logic at the
     * end of a conversation, you can simply call the callback directly.
     *
     * @param id The identifer of the conversation that was entered
     * @param ctx The current context object
     */
    onExit?(id: string, ctx: OC): unknown | Promise<unknown>;
}
/**
 * Internal conversation data representation. Holds the state of any number of
 * conversations for each conversation identifier.
 */
export interface ConversationData {
    [id: string]: ConversationState[];
}
/**
 * Context flavor for the outside middleware tree. Installs `ctx.conversation`
 * on the type of a context object so it can be used to enter or exit
 * conversations as well as inspect active conversations.
 *
 * This should only be installed if you install the {@link conversations}
 * middleware.
 *
 * Note that it is not possible to use the conversations plugin recursively
 * inside conversations. In other words `ctx.conversation` does not exist inside
 * a conversation. Consequently, it is always incorrect to install this context
 * flavor for context objects inside conversations.
 */
export type ConversationFlavor<C extends Context> = C & {
    /**
     * Controls for entering or exiting conversations from the outside
     * middleware. Also provides a way to inspect which conversations are
     * currently active.
     */
    conversation: ConversationControls;
};
/**
 * A control panel for all known conversations. This holds the `enter` method
 * that is the main entrypoint to a conversation.
 *
 * In addition, conversations can be killed from the outside using one of the
 * exit methods.
 *
 * Finally, the control panel can be used to inspect which conversations are
 * currently active.
 */
export interface ConversationControls {
    /**
     * Enters the conversation with the given identifer. By default, the name of
     * the function is the identifier of the function. You can override this
     * value when calling {@link createConversation}.
     *
     * ```ts
     * // Enters a conversation called "convo" upon a start command.
     * bot.command("start", async ctx => {
     *   await ctx.conversation.enter("convo")
     * })
     * ```
     *
     * Entering a conversation will make the conversation run partially until
     * the first wait call is reached. The enter call will therefore return long
     * before the conversation has returned.
     *
     * You can pass any number of arguments when entering a conversation. These
     * arguments will be serialized to JSON and persisted in the storage as
     * `string`. Whenever the conversation is replayed, this string is parsed
     * back to objects and supplied to the conversation. This means that all
     * arguments must be JSON-serializable.
     *
     * ```ts
     * // Enters a conversation called "convo" upon a start command.
     * bot.command("start", async ctx => {
     *   await ctx.conversation.enter("convo", 42, "cool", { args: [2, 1, 0] })
     * })
     * async function convo(conversation, ctx, num, str, { args }) {
     *   // ...
     * }
     * ```
     *
     * Be careful: There is no type safety for conversation arguments! You must
     * annotate the correct types in the function signature of the conversation
     * builder function, and you also have to make sure that you pass matching
     * values to `enter`.
     *
     * This method will throw an error if the same or a different conversation
     * has already been entered. If you want to enter a conversations in
     * parallel to existing active conversations, you can mark it as parallel.
     * This can be done by passig `{ parallel: true }` to
     * {@link createConversation}.
     *
     * @param name The identifer of the conversation to enter
     * @param args Optional list of arguments
     */
    enter(name: string, ...args: unknown[]): Promise<void>;
    /**
     * Purges all state of the conversation with the given identifer for the
     * current chat. This means that if the specified conversation had been
     * active, it is now terminated. If the conversation was marked as parallel,
     * all conversations with this identifier are left for the current chat.
     *
     * Note that if you call this method concurrently to a replay, the replay
     * will not be interrupted. However, its data will not be saved as soon as
     * the replay finishes.
     *
     * For every exited conversation, `onExit` will be called if specified when
     * installing the conversations plugin.
     *
     * Does nothing if no conversation with the given name is active in the
     * current chat.
     *
     * @param name The identifier of the conversation to exit
     */
    exit(name: string): Promise<void>;
    /**
     * Purges all state of all conversations in the current chat, irrespective
     * of their identifers. This will terminate all conversations.
     *
     * Note that if you call this method concurrently to a replay, the replay
     * will not be interrupted. However, its data will not be saved as soon as
     * the replay finishes.
     *
     * For every exited conversation, `onExit` will be called if specified when
     * installing the conversations plugin.
     *
     * Does nothing if no conversations are running.
     */
    exitAll(): Promise<void>;
    /**
     * Purges all state of the conversation with the given identifer at the
     * given position for the current chat. This means that if the specified
     * conversation had been active, it is now terminated. The position is
     * determined chronologically. For example, passing `0` will exit the oldest
     * parallel conversation with the given identifier that is still active.
     *
     * Note that if you call this method concurrently to a replay, the replay
     * will not be interrupted. However, its data will not be saved as soon as
     * the replay finishes.
     *
     * `onExit` will be called if specified when installing the conversations
     * plugin.
     *
     * Does nothing if no conversation with the given name is active at the
     * given position in the current chat.
     *
     * @param name The identifier of the conversation to exit
     * @param index The position of the conversation to exit
     */
    exitOne(name: string, index: number): Promise<void>;
    /**
     * Returns an object specifying the number of times that each conversation
     * is currently active. For example, if a parallel conversation called
     * "captcha" is active 3 times in the current chat, and a conversation
     * called "settings" is active once in the same chat, the returned object
     * will look like this.
     *
     * ```ts
     * {
     *   captcha: 3,
     *   settings: 1,
     * }
     * ```
     */
    active(): Record<string, number>;
    /**
     * Returns the number of times that a given conversation is active in the
     * current chat. If no conversation was marked as parallel, this value will
     * always only be either `0` or `1`.
     *
     * For example, this is how you can check if a conversation called
     * "birthday" is currently active.
     *
     * ```ts
     * if (ctx.conversation.active("birthday")) {
     *   // birthday conversation is active
     * }
     * // same but more explicit:
     * if (ctx.conversation.active("birthday") > 0) {
     *   // birthday conversation is active
     * }
     * ```
     *
     * @param name
     */
    active(name: string): number;
}
/**
 * Middleware for the conversations plugin.
 *
 * This is the main thing you have to install in order to use this plugin. It
 * performs various setup tasks for each context object, and it reads and writes
 * to the data storage if provided. This middleware has to be installed before
 * you can install `createConversation` with your conversation builder function.
 *
 * You can pass {@link ConversationOptions | an options object} to the plugin.
 * The most important option is called `storage`. It can be used to persist
 * conversations durably in any storage backend of your choice. That way, the
 * conversations can survive restarts of your server.
 *
 * ```ts
 * conversations({
 *   storage: {
 *     type: "key",
 *     version: 0, // change the version when you change your code
 *     adapter: new FileAdapter("/home/bot/data"),
 *   },
 * });
 * ```
 *
 * A list of known storage adapters can be found
 * [here](https://github.com/grammyjs/storages/tree/main/packages#grammy-storages).
 *
 * It is advisable to version your data when you persist it. Every time you
 * change your conversation function, you can increment the version. That way,
 * the conversations plugin can make sure to avoid any data corruption caused by
 * mismatches between state and implementation.
 *
 * Note that the plugin takes two different type parameters. The first type
 * parameter should corresopnd with the context type of the outside middleware
 * tree. The second type parameter should correspond with the custom context
 * type used inside all conversations. If you may want to use different context
 * types for different conversations, you can simply use `Context` here, and
 * adjust the type for each conversation individually.
 *
 * Be sure to read [the documentation about the conversations
 * plugin](https://grammy.dev/plugins/conversations) to learn more about how to
 * use it.
 *
 * @param options Optional options for the conversations plugin
 * @typeParam OC Custom context type of the outside middleware
 * @typeParam C Custom context type used inside conversations
 */
export declare function conversations<OC extends Context, C extends Context>(options?: ConversationOptions<OC, C>): MiddlewareFn<ConversationFlavor<OC>>;
/**
 * State of a single conversation.
 *
 * Objects of this type are persisted when a conversation is interrupted and the
 * state of execution is stored in the database.
 */
export interface ConversationState {
    /** JSON string of the arguments supplied to a conversation */
    args?: string;
    /** The replay state containing the state of execution */
    replay: ReplayState;
    /** A list of pending interrupts that can be resolved */
    interrupts: number[];
}
/**
 * A result of running a conversation builder function.
 *
 * This is a union of four possible outcomes of the replay. The union members
 * are discriminated by their `status` property. The replay may have completed
 * normally, thrown an error, or consumed or skipped the update.
 */
export type ConversationResult = ConversationComplete | ConversationError | ConversationHandled | ConversationSkipped;
/**
 * A conversation result indicating that the conversation has completed normally
 * by returning.
 */
export interface ConversationComplete {
    /** New status of the conversation, always `"complete"` */
    status: "complete";
    /** Whether the conversation demands downstream middleware to be called */
    next: boolean;
}
/**
 * A conversation result indicating that the conversation has completed by
 * throwing an error.
 */
export interface ConversationError {
    /** New status of the conversation, always `"error"` */
    status: "error";
    /** The thrown error object */
    error: unknown;
}
/**
 * A conversation result indicating that the conversation has handled the
 * update. This happens when the conversation builder function was
 * interrupted by calling `wait`.
 *
 * Contains the new replay state which can be used to resume the conversation
 * further. Also contains a list of pending interrupts which identify the
 * unresolved `wait` calls.
 */
export interface ConversationHandled {
    /** New status of the conversation, always `"handled"` */
    status: "handled";
    /** The new replay state after handling the update */
    replay: ReplayState;
    /** A list of pending interrupts to resume the conversation */
    interrupts: number[];
}
/**
 * A conversation result indicating that the conversation has decided to skip
 * handling this update. This happens when the conversation builder function
 * cancels the execution using `skip`.
 */
export interface ConversationSkipped {
    /** New status of the conversation, always `"skipped"` */
    status: "skipped";
    /** Whether the conversation demands downstream middleware to be called */
    next: boolean;
}
/**
 * A conversation builder function.
 *
 * This is the type of function that defines a conversation. Conversation buider
 * functions receive as their first argument an instance of
 * {@link Conversation}. This allows them to wait for updates and control the
 * conversation in various other ways.
 *
 * As a second argument, the first context object is received. This context
 * object contains the update that was used to enter the conversation.
 *
 * Any additional arguments are the values provided to the enter call. Note that
 * there is no type safety for these parameters.
 *
 * @param conversation A conversation handle
 * @param ctx The initial context object
 * @typeParam OC Custom context type of the outside middleware
 * @typeParam C Custom context type used inside conversations
 */
export type ConversationBuilder<OC extends Context, C extends Context> = (conversation: Conversation<OC, C>, ctx: C, ...args: any[]) => Promise<unknown> | unknown;
/**
 * Configuration options for a conversation. These options can be passed to
 * {@link createConversation} when installing the conversation.
 *
 * @typeParam C The type of context object used inside this conversation
 */
export interface ConversationConfig<C extends Context> {
    /**
     * Identifier of the conversation. The identifier can be used to enter or
     * exit conversations from middleware.
     *
     * Defaults to [the JavaScript function
     * name](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name).
     */
    id?: string;
    /**
     * An array of plugins to be installed on every context object created by
     * the conversation.
     *
     * Remember that when a conversation is executed, it creates a number of
     * context objects from scratch during each replay. If this is not obvious
     * to you, it means that you probably should read [the documentation of this
     * plugin](https://grammy.dev/plugins/conversations) in order to avoid
     * common pitfalls.
     *
     * The created context objects did not pass through the middleware tree, so
     * they will not have any properties installed on them. You can use this
     * configuration option to specify a number of grammY plugins that should
     * receive each context object created by the conversation.
     *
     * This lets you use many plugins inside the conversation. However, there
     * are still a few things to be aware of. In a typical middleware pass,
     * every plugin can process a context object, then call `next` to wait for
     * downstream middleware to finish, and then get the opportunity to perform
     * cleanup tasks or execute other code after the update was processed
     * downstream.
     *
     * Passing middleware to the `plugins` array will behave differently in the
     * sense that a call to `next` will resolve immediately. The context object
     * is given to the conversation only after all plugins have processed it.
     * Plugins that depend on executing tasks after calling `next` therefore
     * will not work correctly.
     *
     * If a plugin decides to fully handle an update by not calling `next`, then
     * this will consume the update. Any pending `wait` calls inside the
     * conversation will only receive the next incoming update.
     *
     * Note that you can install Bot API transformers from inside middleware,
     * too. This lets you modify the instances of `Api` created by the
     * conversations plugin.
     *
     * ```ts
     * plugins: [async (ctx, next) => {
     *   ctx.api.config.use(transformer)
     *   await next()
     * }]
     * ```
     *
     * In some cases, TypeScript is known not to be able to infer the correct
     * context type for plugins passed to this configuration option. The types
     * are still checked, though, which leads to compilation errors. They can be
     * fixed by passing the custom context type to the plugins explicitly. Note
     * that you need to use the custom context type used inside the
     * conversation, not the custom context type used in the outside middleware.
     */
    plugins?: Middleware<C>[];
    /**
     * Specifies a default timeout for all wait calls inside the conversation.
     *
     * This value can be overridden for each wait call by passing a different
     * timeout value.
     */
    maxMillisecondsToWait?: number;
    /**
     * Marks the conversation as parallel.
     *
     * By default, only a single conversation can ben active per chat. When this
     * option is set to `true`, this conversation can be entered when a
     * different conversation with the same or a different identifier is already
     * active. For example, in a single group chat, you can have 10 different
     * active conversations with 10 different users all at the same time.
     *
     * Conversations from different chats are always parallel.
     *
     * Only a single conversation can handle an update. When multiple
     * conversations are active at the same time in a chat, only the first
     * conversation will receive the update. If it decides to skip the update,
     * the second conversation will receive the update. This order is determined
     * by the order in which the different conversations are installed in the
     * middleware tree. If multiple conversations with the same identifer are
     * active, they will recieve the update in chronological order of the time
     * that the conversations were entered.
     *
     * By default, when a conversation decides to skip an update, the update
     * will be dropped. When a conversation is marked as parallel, it will
     * default to returning the update to the middleware system so that other
     * active conversations can pick up the update and handle it. This also
     * means that if you mark a conversation as parallel, unrelated downstream
     * middleware might process the update.
     *
     * When an update is skipped, an option `next` can be passed to override the
     * above behavior. This lets you decide for every call to `skip` whether
     * parallel conversations as well as other middleware shall receive an
     * update, or whether the update should be dropped. The same option exists
     * for filtered wait calls, chained wait calls, and conversational forms.
     *
     * Defaults to `false`.
     */
    parallel?: boolean;
}
/**
 * Takes a {@link ConversationBuilder | conversation builder function}, and
 * turns it into middleware that can be installed on your bot. This middleware
 * registers the conversation on the context object. Downstream handlers can
 * then enter the conversation using `ctx.conversation.enter`.
 *
 * When an update reaches this middleware and the given conversation is
 * currently active, then it will receive the update and process it. This
 * advances the conversation.
 *
 * If the conversation is marked as parallel, downstream middleware will be
 * called if this conversation decides to skip the update.
 *
 * You can pass a second parameter of type string to this function in order to
 * give a different identifier to the conversation. By default, [the name of the
 * function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name)
 * is used.
 *
 * ```ts
 * bot.use(createConversation(example, "new-name"))
 * ```
 *
 * Optionally, instead of passing an identifier string as a second argument, you
 * can pass an options object. It lets you configure the conversation. For example, this is how you can mark a conversation as parallel.
 *
 * ```ts
 * bot.use(createConversation(example, {
 *   id: "new-name",
 *   parallel: true,
 * }))
 * ```
 *
 * Note that this function takes two different type parameters. The first type
 * parameter should corresopnd with the context type of the outside middleware
 * tree. The second type parameter should correspond with the custom context
 * type used inside the given conversation. These two custom context types can
 * never be identical because the outside middleware must have
 * {@link ConversationFlavor} installed, but the custom context type used in the
 * conversation must never have this type installed.
 *
 * @param builder A conversation builder function
 * @param options A different name for the conversation, or an options object
 * @typeParam OC Custom context type of the outside middleware
 * @typeParam C Custom context type used inside this conversation
 */
export declare function createConversation<OC extends Context, C extends Context>(builder: ConversationBuilder<OC, C>, options?: string | ConversationConfig<C>): MiddlewareFn<ConversationFlavor<OC>>;
/**
 * Takes a conversation builder function and some state and runs all parallel
 * instances of it until a conversation result was produced.
 *
 * This is used internally to run a conversation, but bots typically don't have
 * to call this method.
 *
 * @param builder A conversation builder function
 * @param base Context base data containing the incoming update
 * @param id The identifier of the conversation
 * @param data The state of execution of all parallel conversations
 * @param options Additional configuration options
 * @typeParam OC Custom context type of the outside middleware
 * @typeParam C Custom context type used inside this conversation
 */
export declare function runParallelConversations<OC extends Context, C extends Context>(builder: ConversationBuilder<OC, C>, base: ContextBaseData, id: string, data: ConversationData, options?: ResumeOptions<OC, C>): Promise<ConversationResult>;
/**
 * A result of entering a conversation builder function.
 *
 * This is a union of four possible outcomes of the initial execution. The union
 * members are discriminated by their `status` property. The execution may have
 * completed normally, thrown an error, or consumed or skipped the update.
 */
export type EnterResult = EnterComplete | EnterError | EnterHandled | EnterSkipped;
/**
 * An enter result indicating that the conversation has immediately completed
 * normally by returning.
 */
export type EnterComplete = ConversationComplete;
/**
 * An enter result indicating that the conversation has completed by throwing an
 * error.
 */
export type EnterError = ConversationError;
/**
 * An enter result indicating that the conversation has handled the update. This
 * happens when the conversation builder function was interrupted by calling
 * `wait`.
 *
 * Contains the created replay state which can be used to resume the
 * conversation further. Also contains a list of pending interrupts which
 * identify the unresolved `wait` calls.
 */
export interface EnterHandled extends ConversationHandled {
    /**
     * A JSON string containing the arguments of the enter call. May be absent
     * if no arguments were provided.
     */
    args?: string;
}
/**
 * An enter result indicating that the conversation has decided to skip handling
 * this update. This happens when the conversation builder function cancels the
 * execution using `skip` immediately after being entered. The conversation will
 * remain active and can handle the next update.
 */
export interface EnterSkipped extends ConversationSkipped {
    /**
     * A JSON string containing the arguments of the enter call. May be absent
     * if no arguments were provided.
     */
    args?: string;
    /** The created replay state after handling the update */
    replay: ReplayState;
    /** A list of pending interrupts to resume the conversation */
    interrupts: number[];
}
/** Options to pass when manually running a conversation from scratch */
export interface EnterOptions<OC extends Context, C extends Context> extends ResumeOptions<OC, C> {
    /** A list of arguments to pass to the conversation */
    args?: unknown[];
}
/**
 * Begins a new execution of a conversation builder function from scratch until
 * a result was produced.
 *
 * This is used internally to enter a conversation, but bots typically don't have
 * to call this method.
 *
 * @param conversation A conversation builder function
 * @param base Context base data containing the incoming update
 * @param options Additional configuration options
 * @typeParam OC Custom context type of the outside middleware
 * @typeParam C Custom context type used inside this conversation
 */
export declare function enterConversation<OC extends Context, C extends Context>(conversation: ConversationBuilder<OC, C>, base: ContextBaseData, options?: EnterOptions<OC, C>): Promise<EnterResult>;
/** Options to pass when manually resuming a conversation */
export interface ResumeOptions<OC extends Context, C extends Context> {
    /** A context object from the outside middleware to use in `external` */
    ctx?: OC;
    /** An array of plugins to run for newly created context objects */
    plugins?: Middleware<C>[];
    /** A callback function to run if `conversation.halt` is called */
    onHalt?(): void | Promise<void>;
    /** A default wait timeout */
    maxMillisecondsToWait?: number;
    /** Whether this conversation is parallel */
    parallel?: boolean;
}
/**
 * Resumes an execution of a conversation builder function until a result was
 * produced.
 *
 * This is used internally to resume a conversation, but bots typically don't
 * have to call this method.
 *
 * @param conversation A conversation builder function
 * @param base Context base data containing the incoming update
 * @param state Previous state of the conversation
 * @param options Additional configuration options
 * @typeParam OC Custom context type of the outside middleware
 * @typeParam C Custom context type used inside this conversation
 */
export declare function resumeConversation<OC extends Context, C extends Context>(conversation: ConversationBuilder<OC, C>, base: ContextBaseData, state: ConversationState, options?: ResumeOptions<OC, C>): Promise<ConversationResult>;
