import { MessageType, FunctionType, ToolType, JSONValueType } from '@axflow/models/shared';

interface AccessorType<T = any> {
    (value: T): string | null | undefined;
}
interface FunctionCallAccessorType<T = any> {
    (value: T): {
        name?: string;
        arguments?: string;
    } | null | undefined;
}
interface ToolCallsAccessorType<T = any> {
    (value: T): Array<{
        index?: number;
        id?: string;
        type?: 'function';
        function: {
            name?: string;
            arguments: string;
        };
    }> | null | undefined;
}
type BodyType = Record<string, JSONValueType> | ((message: MessageType, history: MessageType[]) => JSONValueType);
/**
 * The options supplied to the useChat hook.
 */
type UseChatOptionsType = {
    /**
     * The API endpoint to call when submitting a new message.
     *
     * Defaults to `/api/chat`.
     */
    url?: string;
    /**
     * A function to create unique ids assigned to each message.
     *
     * Defaults to UUID v4 via `crypto.randomUUID`.
     */
    createMessageId?: () => string;
    /**
     * Customize the request body sent to the API using this value. It accepts
     * either a function or object.
     *
     * If given a function, the return value of the function will become the body
     * of the request. The function will be passed the new message as its first
     * argument and the history (an array of previous messages) as its second argument.
     *
     * If given an object, the object will be merged into the request body with the
     * full set of messages, i.e., `{...body, messages }`.
     *
     * By default, the request body is `{ messages }`.
     */
    body?: BodyType;
    /**
     * Additional headers to send along with the request to the API.
     */
    headers?: Record<string, string>;
    /**
     * An accessor used to pluck out the message text. The response body or response
     * stream can send back arbitrary values. If the value sent back is not the message
     * text, then this component needs a way to access the message text. This function
     * is given the value from the API as its input and should return the message text
     * as its output.
     *
     * For example, if this hook is used to stream an OpenAI-compatible API response,
     * the following option can be defined to interpret the response content:
     *
     *     import { useChat } from '@axflow/models/react';
     *     import type { OpenAIChatTypes } from '@axflow/models/openai/chat';
     *
     *     const { ... } = useChat({
     *       accessor: (value: OpenAIChatTypes.Chunk) => {
     *         return value.choices[0].delta.content;
     *       }
     *     });
     *
     * By default, it assumes the value from the API is the message text itself.
     */
    accessor?: AccessorType;
    /**
     * An accessor used to pluck out a function call for LLMs that support it. This
     * feature was built to support OpenAI functions, but it can be used for any model
     * that supports a concept of functions.
     *
     * This is used to return the function call object which will then be populated
     * on the assistant message's `functionCall` property. A function call object
     * consists of a `name` property (the function name) and an `arguments` property
     * (the function arguments), both of which are strings. The `arguments` property
     * is encoded as JSON.
     *
     * For example, if this hook is used to stream an OpenAI-compatible API response
     * using functions, the following options can be defined to interpret the response:
     *
     *     import { useChat } from '@axflow/models/react';
     *     import type { OpenAIChatTypes } from '@axflow/models/openai/chat';
     *
     *     const { ... } = useChat({
     *       accessor: (value: OpenAIChatTypes.Chunk) => {
     *         return value.choices[0].delta.content;
     *       },
     *
     *       functionCallAccessor: (value: OpenAIChatTypes.Chunk) => {
     *         return value.choices[0].delta.function_call;
     *       }
     *     });
     */
    functionCallAccessor?: FunctionCallAccessorType;
    /**
     * An accessor used to pluck out multiple tool calls for LLMs that support it.
     * This is the new nomenclature for openAI's functions, since they now can return
     * multiple in one call.
     *
     * This is used to return the object which will then be populated
     * on the assistant message's `tool_calls` property. A tool_call object
     * consists of a index, id, type (always 'function') and function object
     * with name and parameters, encoded as JSON like for the functionCall above.
     *
     * For example, if this hook is used to stream an OpenAI-compatible API response
     * using openAI tools, the following options can be defined to interpret the response:
     *
     *     import { useChat } from '@axflow/models/react';
     *     import type { OpenAIChatTypes } from '@axflow/models/openai/chat';
     *
     *     const { ... } = useChat({
     *       accessor: (value: OpenAIChatTypes.Chunk) => {
     *         return value.choices[0].delta.content;
     *       },
     *
     *       toolCallsAccessor: (value: OpenAIChatTypes.Chunk) => {
     *         return value.choices[0].delta.tool_calls;
     *       }
     *     });
     */
    toolCallsAccessor?: ToolCallsAccessorType;
    /**
     * Initial message input. Defaults to empty string.
     */
    initialInput?: string;
    /**
     * Initial message history. Defaults to an empty list.
     */
    initialMessages?: MessageType[];
    /**
     * Initial set of available functions for the user's next message.
     *
     * This is primarily intended for OpenAI's functions feature.
     *
     * @see https://platform.openai.com/docs/api-reference/chat/create
     */
    initialFunctions?: FunctionType[];
    /**
     * Initial seet of available tools, which replaced functions, for the user's
     * next message.
     *
     * @see https://platform.openai.com/docs/api-reference/chat/create
     *
     */
    initialTools?: ToolType[];
    /**
     * Callback to handle errors should they arise.
     *
     * Defaults to `console.error`.
     */
    onError?: (error: Error) => void;
    /**
     * Callback that is invoked when the list of messages change.
     *
     * Specifically, it is invoked when:
     *
     *     1. `onSubmit` is invoked and a new user message is added.
     *     2. A new message is received from the server. If streaming, this will
     *        be called each time the message is updated from a streaming event.
     *     3. Any time a client of the hook calls `setMessages`
     */
    onMessagesChange?: (updatedMessages: MessageType[]) => void;
    /**
     * Callback that is invoked when a new message is appended to the list of messages.
     *
     * NOTE: For messages received from the server, this will only be invoked ONE time, when
     * the message is complete. That means, for streaming responses, this will not be invoked
     * until the stream has finished and the message is complete. If you want to get notified
     * for each update, the `onMessagesChange` callback fires every time the list of messages
     * changes, which includes message updates from streaming responses.
     */
    onNewMessage?: (message: MessageType) => void;
};
/**
 * The result of invoking the useChat hook.
 */
type UseChatResultType = {
    /**
     * Current user's message input.
     */
    input: string;
    /**
     * Manually set the input.
     */
    setInput: (input: string) => void;
    /**
     * The history of messages so far in this chat.
     */
    messages: MessageType[];
    /**
     * Manually set the messages.
     */
    setMessages: (messages: MessageType[]) => void;
    /**
     * List of available functions to send along with the next user message.
     *
     * This is primarily intended for OpenAI's functions feature.
     *
     * @see https://platform.openai.com/docs/api-reference/chat/create
     */
    functions: FunctionType[];
    /**
     * Update list of functions for the next user message.
     *
     * This is primarily intended for OpenAI's functions feature.
     *
     * @see https://platform.openai.com/docs/api-reference/chat/create
     */
    setFunctions: (functions: FunctionType[]) => void;
    /**
     * Update list of tools for the next user message.
     *
     * This is primarily intended for OpenAI's tools feature.
     *
     * @see https://platform.openai.com/docs/api-reference/chat/create
     */
    setTools: (tools: ToolType[]) => void;
    /**
     * If a request is in progress, this will be `true`.
     *
     * For streaming requests, `loading` will be `true` from the time the request is
     * first sent until the stream has closed. For non-streaming requests, it is `true`
     * until a response is received.
     */
    loading: boolean;
    /**
     * If a request fails, this will be populated with the `Error`. This will be reset
     * to `null` upon the next request.
     *
     * See also the `onError` callback option.
     */
    error: Error | null;
    /**
     * A handler to change the user's message input.
     *
     * @param e Either a form field change event or the string representing the changed user input.
     */
    onChange: (e: React.ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLTextAreaElement> | string) => void;
    /**
     * A handler to trigger submission to the API.
     *
     * @param e Optional `React.FormEvent<HTMLFormElement>` if this value is used with a Form.
     */
    onSubmit: (e?: React.FormEvent<HTMLFormElement>) => void;
    /**
     * Sends a request to the server with the current list of messages for a new assistant response.
     *
     * Note:
     *
     *     * If there are no `user` or `system` messages in the list, this function will throw an error.
     *     * If there are assistant messages more recent than the last `user` or `system` message, they will
     *       be removed from the list of messages before sending a request to the server.
     */
    reload: () => void;
};
/**
 * A React hook to power LLM chat applications.
 *
 * This hook supports streaming and non-streaming responses. If streaming, the API
 * response must have a content-type header set to `application/x-ndjson; charset=utf-8`.
 * Additionally, it must send its JSON chunks using the following format:
 *
 *     { type: 'data' | 'chunk', value: <any valid JSON value> }
 *
 * When `type` is `chunk`, `value` represents a chunk of the source stream. When `type`
 * is `data`, `value` represents any additional data sent along with the source stream.
 *
 * @param options UseChatOptionsType
 * @returns UseChatResultType
 */
declare function useChat(options?: UseChatOptionsType): UseChatResultType;

export { UseChatOptionsType, UseChatResultType, useChat };
