import { LanguageModelV2 } from '@ai-sdk/provider';
import { ProviderOptions, InferSchema } from '@ai-sdk/provider-utils';
import { ReactNode } from 'react';
import * as z3 from 'zod/v3';
import * as z4 from 'zod/v4';
import { Schema, CallSettings, Prompt, ToolChoice, FinishReason, LanguageModelUsage, CallWarning } from 'ai';

type JSONValue = string | number | boolean | JSONObject | JSONArray;
interface JSONObject {
    [x: string]: JSONValue;
}
interface JSONArray extends Array<JSONValue> {
}
type AIAction<T = any, R = any> = (...args: T[]) => Promise<R>;
type AIActions<T = any, R = any> = Record<string, AIAction<T, R>>;
type ServerWrappedAction<T = unknown> = (aiState: T, ...args: unknown[]) => Promise<[Promise<T>, unknown]>;
type ServerWrappedActions<T = unknown> = Record<string, ServerWrappedAction<T>>;
type InternalAIProviderProps<AIState = any, UIState = any> = {
    children: React.ReactNode;
    initialUIState: UIState;
    initialAIState: AIState;
    initialAIStatePatch: undefined | Promise<AIState>;
    wrappedActions: ServerWrappedActions<AIState>;
    wrappedSyncUIState?: ServerWrappedAction<AIState>;
};
type AIProviderProps<AIState = any, UIState = any, Actions = any> = {
    children: React.ReactNode;
    initialAIState?: AIState;
    initialUIState?: UIState;
    /** $ActionTypes is only added for type inference and is never used at runtime **/
    $ActionTypes?: Actions;
};
type AIProvider<AIState = any, UIState = any, Actions = any> = (props: AIProviderProps<AIState, UIState, Actions>) => Promise<React.ReactElement>;
type InferAIState<T, Fallback> = T extends AIProvider<infer AIState, any, any> ? AIState : Fallback;
type InferUIState<T, Fallback> = T extends AIProvider<any, infer UIState, any> ? UIState : Fallback;
type InferActions<T, Fallback> = T extends AIProvider<any, any, infer Actions> ? Actions : Fallback;
type InternalAIStateStorageOptions = {
    onSetAIState?: OnSetAIState<any>;
};
type OnSetAIState<S> = ({ key, state, done, }: {
    key: string | number | symbol | undefined;
    state: S;
    done: boolean;
}) => void | Promise<void>;
type OnGetUIState<S> = AIAction<void, S | undefined>;
type ValueOrUpdater<T> = T | ((current: T) => T);
type MutableAIState<AIState> = {
    get: () => AIState;
    update: (newState: ValueOrUpdater<AIState>) => void;
    done: ((newState: AIState) => void) | (() => void);
};

/**
 * Get the current AI state.
 * If `key` is provided, it will return the value of the specified key in the
 * AI state, if it's an object. If it's not an object, it will throw an error.
 *
 * @example const state = getAIState() // Get the entire AI state
 * @example const field = getAIState('key') // Get the value of the key
 */
declare function getAIState<AI extends AIProvider = any>(): Readonly<InferAIState<AI, any>>;
declare function getAIState<AI extends AIProvider = any>(key: keyof InferAIState<AI, any>): Readonly<InferAIState<AI, any>[typeof key]>;
/**
 * Get the mutable AI state. Note that you must call `.done()` when finishing
 * updating the AI state.
 *
 * @example
 * ```tsx
 * const state = getMutableAIState()
 * state.update({ ...state.get(), key: 'value' })
 * state.update((currentState) => ({ ...currentState, key: 'value' }))
 * state.done()
 * ```
 *
 * @example
 * ```tsx
 * const state = getMutableAIState()
 * state.done({ ...state.get(), key: 'value' }) // Done with a new state
 * ```
 */
declare function getMutableAIState<AI extends AIProvider = any>(): MutableAIState<InferAIState<AI, any>>;
declare function getMutableAIState<AI extends AIProvider = any>(key: keyof InferAIState<AI, any>): MutableAIState<InferAIState<AI, any>[typeof key]>;

declare function createAI<AIState = any, UIState = any, Actions extends AIActions = {}>({ actions, initialAIState, initialUIState, onSetAIState, onGetUIState, }: {
    actions: Actions;
    initialAIState?: AIState;
    initialUIState?: UIState;
    /**
     * This function is called whenever the AI state is updated by an Action.
     * You can use this to persist the AI state to a database, or to send it to a
     * logging service.
     */
    onSetAIState?: OnSetAIState<AIState>;
    /**
     * This function is used to retrieve the UI state based on the AI state.
     * For example, to render the initial UI state based on a given AI state, or
     * to sync the UI state when the application is already loaded.
     *
     * If returning `undefined`, the client side UI state will not be updated.
     *
     * This function must be annotated with the `"use server"` directive.
     *
     * @example
     * ```tsx
     * onGetUIState: async () => {
     *   'use server';
     *
     *   const currentAIState = getAIState();
     *   const externalAIState = await loadAIStateFromDatabase();
     *
     *   if (currentAIState === externalAIState) return undefined;
     *
     *   // Update current AI state and return the new UI state
     *   const state = getMutableAIState()
     *   state.done(externalAIState)
     *
     *   return <div>...</div>;
     * }
     * ```
     */
    onGetUIState?: OnGetUIState<UIState>;
}): AIProvider<AIState, UIState, Actions>;

type Streamable = ReactNode | Promise<ReactNode>;
type Renderer<T extends Array<any>> = (...args: T) => Streamable | Generator<Streamable, Streamable, void> | AsyncGenerator<Streamable, Streamable, void>;
type RenderTool<INPUT_SCHEMA extends z4.core.$ZodType | z3.Schema | Schema = any> = {
    description?: string;
    inputSchema: INPUT_SCHEMA;
    generate?: Renderer<[
        InferSchema<INPUT_SCHEMA>,
        {
            toolName: string;
            toolCallId: string;
        }
    ]>;
};
type RenderText = Renderer<[
    {
        /**
         * The full text content from the model so far.
         */
        content: string;
        /**
         * The new appended text content from the model since the last `text` call.
         */
        delta: string;
        /**
         * Whether the model is done generating text.
         * If `true`, the `content` will be the final output and this call will be the last.
         */
        done: boolean;
    }
]>;
type RenderResult = {
    value: ReactNode;
} & Awaited<ReturnType<LanguageModelV2['doStream']>>;
/**
 * `streamUI` is a helper function to create a streamable UI from LLMs.
 */
declare function streamUI<TOOLS extends {
    [name: string]: z4.core.$ZodType | z3.Schema | Schema;
} = {}>({ model, tools, toolChoice, system, prompt, messages, maxRetries, abortSignal, headers, initial, text, providerOptions, onFinish, ...settings }: CallSettings & Prompt & {
    /**
     * The language model to use.
     */
    model: LanguageModelV2;
    /**
     * The tools that the model can call. The model needs to support calling tools.
     */
    tools?: {
        [name in keyof TOOLS]: RenderTool<TOOLS[name]>;
    };
    /**
     * The tool choice strategy. Default: 'auto'.
     */
    toolChoice?: ToolChoice<TOOLS>;
    text?: RenderText;
    initial?: ReactNode;
    /**
Additional provider-specific options. They are passed through
to the provider from the AI SDK and enable provider-specific
functionality that can be fully encapsulated in the provider.
 */
    providerOptions?: ProviderOptions;
    /**
     * Callback that is called when the LLM response and the final object validation are finished.
     */
    onFinish?: (event: {
        /**
         * The reason why the generation finished.
         */
        finishReason: FinishReason;
        /**
         * The token usage of the generated response.
         */
        usage: LanguageModelUsage;
        /**
         * The final ui node that was generated.
         */
        value: ReactNode;
        /**
         * Warnings from the model provider (e.g. unsupported settings)
         */
        warnings?: CallWarning[];
        /**
         * Optional response data.
         */
        response?: {
            /**
             * Response headers.
             */
            headers?: Record<string, string>;
        };
    }) => Promise<void> | void;
}): Promise<RenderResult>;

type StreamableUIWrapper = {
    /**
     * The value of the streamable UI. This can be returned from a Server Action and received by the client.
     */
    readonly value: React.ReactNode;
    /**
     * This method updates the current UI node. It takes a new UI node and replaces the old one.
     */
    update(value: React.ReactNode): StreamableUIWrapper;
    /**
     * This method is used to append a new UI node to the end of the old one.
     * Once appended a new UI node, the previous UI node cannot be updated anymore.
     *
     * @example
     * ```jsx
     * const ui = createStreamableUI(<div>hello</div>)
     * ui.append(<div>world</div>)
     *
     * // The UI node will be:
     * // <>
     * //   <div>hello</div>
     * //   <div>world</div>
     * // </>
     * ```
     */
    append(value: React.ReactNode): StreamableUIWrapper;
    /**
     * This method is used to signal that there is an error in the UI stream.
     * It will be thrown on the client side and caught by the nearest error boundary component.
     */
    error(error: any): StreamableUIWrapper;
    /**
     * This method marks the UI node as finalized. You can either call it without any parameters or with a new UI node as the final state.
     * Once called, the UI node cannot be updated or appended anymore.
     *
     * This method is always **required** to be called, otherwise the response will be stuck in a loading state.
     */
    done(...args: [React.ReactNode] | []): StreamableUIWrapper;
};
/**
 * Create a piece of changeable UI that can be streamed to the client.
 * On the client side, it can be rendered as a normal React node.
 */
declare function createStreamableUI(initialValue?: React.ReactNode): StreamableUIWrapper;

declare const __internal_curr: unique symbol;
declare const __internal_error: unique symbol;
/**
 * StreamableValue is a value that can be streamed over the network via AI Actions.
 * To read the streamed values, use the `readStreamableValue` or `useStreamableValue` APIs.
 */
type StreamableValue<T = any, E = any> = {
    [__internal_curr]?: T;
    [__internal_error]?: E;
};

/**
 * Create a wrapped, changeable value that can be streamed to the client.
 * On the client side, the value can be accessed via the readStreamableValue() API.
 */
declare function createStreamableValue<T = any, E = any>(initialValue?: T | ReadableStream<T>): StreamableValueWrapper<T, E>;
type StreamableValueWrapper<T, E> = {
    /**
     * The value of the streamable. This can be returned from a Server Action and
     * received by the client. To read the streamed values, use the
     * `readStreamableValue` or `useStreamableValue` APIs.
     */
    readonly value: StreamableValue<T, E>;
    /**
     * This method updates the current value with a new one.
     */
    update(value: T): StreamableValueWrapper<T, E>;
    /**
     * This method is used to append a delta string to the current value. It
     * requires the current value of the streamable to be a string.
     *
     * @example
     * ```jsx
     * const streamable = createStreamableValue('hello');
     * streamable.append(' world');
     *
     * // The value will be 'hello world'
     * ```
     */
    append(value: T): StreamableValueWrapper<T, E>;
    /**
     * This method is used to signal that there is an error in the value stream.
     * It will be thrown on the client side when consumed via
     * `readStreamableValue` or `useStreamableValue`.
     */
    error(error: any): StreamableValueWrapper<T, E>;
    /**
     * This method marks the value as finalized. You can either call it without
     * any parameters or with a new value as the final state.
     * Once called, the value cannot be updated or appended anymore.
     *
     * This method is always **required** to be called, otherwise the response
     * will be stuck in a loading state.
     */
    done(...args: [T] | []): StreamableValueWrapper<T, E>;
};

/**
 * `readStreamableValue` takes a streamable value created via the `createStreamableValue().value` API,
 * and returns an async iterator.
 *
 * ```js
 * // Inside your AI action:
 *
 * async function action() {
 *   'use server'
 *   const streamable = createStreamableValue();
 *
 *   streamable.update(1);
 *   streamable.update(2);
 *   streamable.done(3);
 *   // ...
 *   return streamable.value;
 * }
 * ```
 *
 * And to read the value:
 *
 * ```js
 * const streamableValue = await action()
 * for await (const v of readStreamableValue(streamableValue)) {
 *   console.log(v)
 * }
 * ```
 *
 * This logs out 1, 2, 3 on console.
 */
declare function readStreamableValue<T = unknown>(streamableValue: StreamableValue<T>): AsyncIterable<T | undefined>;

/**
 * `useStreamableValue` is a React hook that takes a streamable value created via the `createStreamableValue().value` API,
 * and returns the current value, error, and pending state.
 *
 * This is useful for consuming streamable values received from a component's props. For example:
 *
 * ```js
 * function MyComponent({ streamableValue }) {
 *   const [data, error, pending] = useStreamableValue(streamableValue);
 *
 *   if (pending) return <div>Loading...</div>;
 *   if (error) return <div>Error: {error.message}</div>;
 *
 *   return <div>Data: {data}</div>;
 * }
 * ```
 */
declare function useStreamableValue<T = unknown, Error = unknown>(streamableValue?: StreamableValue<T>): [data: T | undefined, error: Error | undefined, pending: boolean];

declare function useUIState<AI extends AIProvider = any>(): [InferUIState<AI, any>, (v: InferUIState<AI, any> | ((v_: InferUIState<AI, any>) => InferUIState<AI, any>)) => void];
declare function useAIState<AI extends AIProvider = any>(): [
    InferAIState<AI, any>,
    (newState: ValueOrUpdater<InferAIState<AI, any>>) => void
];
declare function useAIState<AI extends AIProvider = any>(key: keyof InferAIState<AI, any>): [
    InferAIState<AI, any>[typeof key],
    (newState: ValueOrUpdater<InferAIState<AI, any>[typeof key]>) => void
];
declare function useActions<AI extends AIProvider = any>(): InferActions<AI, any>;
declare function useSyncUIState(): () => Promise<void>;

export { AIAction, AIActions, AIProvider, AIProviderProps, InferAIState, InferActions, InferUIState, InternalAIProviderProps, InternalAIStateStorageOptions, JSONValue, MutableAIState, OnGetUIState, OnSetAIState, ServerWrappedAction, ServerWrappedActions, StreamableValue, ValueOrUpdater, createAI, createStreamableUI, createStreamableValue, getAIState, getMutableAIState, readStreamableValue, streamUI, useAIState, useActions, useStreamableValue, useSyncUIState, useUIState };
