import { AnalyticsConfig } from '@yext/analytics';
import { ApiError } from '@yext/chat-core';
import { ChatConfig } from '@yext/chat-core';
import { DeepPartial } from '@reduxjs/toolkit';
import { EndEvent } from '@yext/chat-core';
import { Endpoints } from '@yext/chat-core';
import { Environment } from '@yext/chat-core';
import { EventPayload } from '@yext/analytics';
import { Message } from '@yext/chat-core';
import { MessageNotes } from '@yext/chat-core';
import { MessageRequest } from '@yext/chat-core';
import { MessageResponse } from '@yext/chat-core';
import { MessageSource } from '@yext/chat-core';
import { RawResponse } from '@yext/chat-core';
import { Region } from '@yext/chat-core';
import { StartEvent } from '@yext/chat-core';
import { Store } from '@reduxjs/toolkit';
import { StreamEvent } from '@yext/chat-core';
import { StreamEventCallback } from '@yext/chat-core';
import { StreamEventName } from '@yext/chat-core';
import { StreamResponse } from '@yext/chat-core';
import { TokenStreamEvent } from '@yext/chat-core';
import { Unsubscribe } from '@reduxjs/toolkit';

export { ApiError }

/**
 * A client that can be used to process user messages and provide responses.
 *
 * @public
 */
export declare type ChatClient = ChatHttpClient | ChatEventClient;

export { ChatConfig }

/**
 * An event-driven client for processing user message and provide responses
 * by emitting and listening to events.
 *
 * @public
 */
export declare interface ChatEventClient {
    /**
     * Initializes the client, using credentials and data in the provided message to setup a chat session.
     *
     * @param messageResponse - The message response that initiated the handoff to the chat client.
     */
    init(messageResponse: MessageResponse): Promise<any>;
    /**
     * Registers an event listener for a specified event.
     * Supported events are:
     * - `message`: A new message has been received.
     * - `typing`: The agent is typing.
     * - `close`: The chat session has been closed.
     *
     * @param eventName - The name of the event to listen to.
     * @param cb - The callback function to be executed when the event is triggered.
     */
    on(eventName: "message" | "typing" | "close", cb: (data: any) => void): void;
    /**
     * Emits an event with the specified name and data, triggering all registered listeners for that event.
     *
     * @param eventName - The name of the event to emit.
     * @param data  - The data to be passed to the event listeners.
     */
    emit(eventName: string, data: any): void;
    /**
     * Processes a message request. The response should be emitted as a message event.
     *
     * @param request - The message request to process.
     */
    processMessage(request: MessageRequest): Promise<void>;
    /**
     * Provide the current chat session.
     */
    getSession(): any;
    /**
     * Reset the current chat session.
     */
    resetSession(): void;
    /**
     * Reinitialize the session using existing session data.
     */
    reinitializeSession(credentials: any): Promise<void>;
}

/**
 * Provides the functionality needed to interact with the Chat API in a
 * stateful manner.
 *
 * @public
 */
export declare interface ChatHeadless {
    /**
     * Gets the current state of the ChatHeadless instance.
     *
     * @public
     */
    get state(): State;
    /**
     * Sets the {@link State} to the specified state.
     *
     * @public
     *
     * @param state - The state to set
     */
    setState(state: State): void;
    /* Excluded from this release type: store */
    /**
     * Sets {@link MetaState.context} to the specified context.
     *
     * @public
     *
     * @param context - The context to set
     */
    setContext(context: unknown): void;
    /**
     * Sets {@link ConversationState.messages} to the specified messages
     *
     * @public
     *
     * @param messages - the messages to set
     */
    setMessages(messages: Message[]): void;
    /**
     * Adds a new message to {@link ConversationState.messages}
     *
     * @public
     *
     * @param message - the message to add to state
     */
    addMessage(message: Message): void;
    /**
     * Sets {@link ConversationState.notes} to the specified notes
     *
     * @public
     *
     * @param notes - the notes to set
     */
    setMessageNotes(notes: MessageNotes): void;
    /**
     * Sets {@link ConversationState.isLoading} to the specified loading state
     *
     * @public
     *
     * @param isLoading - the loading state to set
     */
    setChatLoadingStatus(isLoading: boolean): void;
    /**
     * Sets {@link ConversationState.canSendMessage} to the specified state
     *
     * @public
     *
     * @param canSendMessage - the state to set
     */
    setCanSendMessage(canSendMessage: boolean): void;
    /* Excluded from this release type: addClientSdk */
    /**
     * Loads the {@link ConversationState} from local storage, if present,
     * and adds a listener to keep the conversation state in sync with the stored
     * state
     *
     * @remarks
     * This is called by default if {@link HeadlessConfig.saveToLocalStorage} is
     * true.
     *
     * @public
     */
    initLocalStorage(): void;
    /**
     * Resets all fields within the {@link ConversationState}, and sets the active
     * client to the `bot` client, if one was provided when constructing the
     * {@link ChatHeadless} instance.
     *
     * If a {@link ChatEventClient} is currently active before reset, that client's
     * `resetSession` method is called.
     *
     * @public
     */
    restartConversation(): void;
    /**
     * Send Chat related analytics event to Yext Analytics API.
     *
     * @remarks
     * once a CHAT_IMPRESSION analytics event is reported, subsequent
     * CHAT_IMPRESSION reports will not be send.
     *
     * @public
     */
    report(eventPayload: Omit<EventPayload, "chat"> & RecursivePartial<Pick<EventPayload, "chat">>): Promise<void>;
    /**
     * Performs a Chat API request for the next message generated by chat bot
     * using the conversation state (e.g. message history and notes). Update
     * the state with the response data.
     *
     * @public
     *
     * @remarks
     * If rejected, an ApiError is returned.
     * A new message is added to the conversation history only if the provided text is not empty.
     *
     * @param text - the text of the next message
     * @param source - the source of the message
     * @returns a Promise of a response from the Chat API
     */
    getNextMessage(text?: string, source?: MessageSource): Promise<MessageResponse | undefined>;
    /**
     * Adds a listener for a specific state value of type T.
     *
     * @public
     *
     * @param listener - The state listener to add
     * @returns The function for removing the added listener
     */
    addListener<T>(listener: StateListener<T>): Unsubscribe;
    /**
     * Performs a Chat Stream API request for the next message generated
     * by chat bot using the conversation state (e.g. message history and notes).
     * The new message's "text" field is continously updated as tokens from the
     * stream are consumed. Remaining conversation state are updated once the
     * final event from the stream is recieved.
     *
     * @public
     *
     * @experimental
     *
     * @remarks
     * If rejected, an ApiError is returned.
     * A new message is added to the conversation history only if the provided text is not empty.
     *
     * @param text - the text of the next message
     * @param source - the source of the message
     * @returns a Promise of the full response from the Chat Stream API
     */
    streamNextMessage(text?: string, source?: MessageSource): Promise<MessageResponse | undefined>;
}

/**
 * An HTTP-based client for processing user messages and generating
 * corresponding responses via a chat service API.
 *
 * @public
 */
export declare interface ChatHttpClient {
    /**
     * Make a request to generate the next message.
     *
     * @param request - The message request to process.
     */
    getNextMessage(request: MessageRequest): Promise<MessageResponse>;
    /**
     * Make a request to generate the next message and stream its tokens via server-sent events.
     *
     * @param request - The message request to process.
     */
    streamNextMessage(request: MessageRequest): Promise<StreamResponse>;
}

/* Excluded from this release type: ChatPrompt */

/**
 * Maintains the data for the current conversation.
 *
 * @public
 */
export declare interface ConversationState {
    /** The id of the current conversation. */
    conversationId?: string;
    /** The messages in a conversation. */
    messages: Message[];
    /** Information relevant to the current state of the conversation, generated and provided by Chat API. */
    notes?: MessageNotes;
    /** Whether the next message is currently processing or has started responding. */
    isLoading: boolean;
    /**
     * Whether a new message can be sent to Chat API.
     * This is set to false when a previous message is being processed.
     */
    canSendMessage: boolean;
}

export { EndEvent }

export { Endpoints }

export { Environment }

/**
 * The configuration for a SearchHeadless instance.
 *
 * @public
 */
export declare interface HeadlessConfig extends ChatConfig {
    /** Whether to save the instance's {@link ConversationState} to local storage. Defaults to true. */
    saveToLocalStorage?: boolean;
    /** Configurations for Chat analytics. */
    analyticsConfig?: Omit<AnalyticsConfig, "authorizationType" | "authorization" | "env" | "region"> & {
        /** Base payload to include for requests to the Analytics Events API. */
        baseEventPayload?: DeepPartial<EventPayload>;
    };
}

/* Excluded from this release type: InternalConfig */
export { Message }

export { MessageNotes }

export { MessageRequest }

export { MessageResponse }

export { MessageSource }

/**
 * Maintains the metadata for Chat Headless.
 *
 * @public
 */
export declare interface MetaState {
    /**
     * Additional information to pass into the instruction flow. This data could
     * then be used in the URL or body of a REST API step, influence Chat API's
     * assessment in a conditional step, or help construct a reply with additional
     * details.
     *
     * @remarks
     * May be any valid JSON object
     */
    context?: any;
}

/**
 * Provide an instance of {@link ChatHeadless} with all functionality built in.
 *
 * @public
 */
export declare function provideChatHeadless(config: HeadlessConfig, clients?: {
    bot?: ChatClient;
    agent?: ChatClient;
}): ChatHeadless;

/* Excluded from this release type: provideChatHeadlessInternal */
export { RawResponse }

/** Recursively makes all properties of an object optional, adapted for optional nested fields. */
declare type RecursivePartial<T> = {
    [K in keyof T]?: Exclude<T[K], undefined> extends object ? RecursivePartial<T[K]> : T[K];
};

export { Region }

export { StartEvent }

/**
 * The state representing a ChatHeadless instance.
 *
 * @public
 */
export declare interface State {
    /** {@inheritdoc ConversationState} */
    conversation: ConversationState;
    /** {@inheritdoc MetaState} */
    meta: MetaState;
}

/**
 * Represents a listener for a specific value of type T in the state.
 *
 * @public
 */
export declare interface StateListener<T> {
    /**
     * Accesses a value of type T in the state.
     *
     * @param state - The current state
     * @returns The value of type T from the state
     */
    valueAccessor(state: State): T;
    /**
     * The function to call when the state value updates.
     *
     * @param currentValue - The current state value
     */
    callback(currentValue: T): any;
}

export { StreamEvent }

export { StreamEventCallback }

export { StreamEventName }

export { StreamResponse }

export { TokenStreamEvent }

export { }
