import * as _langchain_langgraph from '@langchain/langgraph';
import { KVMap } from 'langsmith/schemas';
import { z } from 'zod';
import { BaseChatModel } from '@langchain/core/language_models/chat_models';

/**
 * Extrai os tipos genéricos Input e Output de um tipo State
 * Usado para facilitar o uso de Procedure com State sem necessidade de
 * recriar os tipos manualmente.
 */
type InferState<T> = T extends State<infer I, infer O> ? State<I, O>["values"] : never;
/**
 * Representa o formato mínimo esperado para os valores de estado
 * utilizados por um agente. Estes valores são normalmente divididos
 * em `input` e `output`.
 */
type StateValuesFormat = {
    /**
     * Propriedades que compõem o estado de **entrada**.
     */
    input: any;
    /**
     * Propriedades que compõem o estado de **saída**.
     */
    output: any;
};
/**
 * A classe `State` controla o estado interno de um agente, contendo
 * tanto as propriedades de **entrada** quanto de **saída** de forma
 * tipada, utilizando `Zod` para validação.
 *
 * @template Input - Schema Zod para o estado de entrada
 * @template Output - Schema Zod para o estado de saída
 */
declare class State<Input extends z.AnyZodObject, Output extends z.AnyZodObject> {
    private readonly props;
    /**
     * Mantém em memória o estado atual do agente, separado em `input` e `output`,
     * ambos tipados e validados via Zod.
     *
     * @private
     */
    private _runtime;
    constructor(props: {
        /**
         * Schema Zod para validar a forma do estado de entrada.
         */
        inputSchema: Input;
        /**
         * Schema Zod para validar a forma do estado de saída.
         */
        outputSchema: Output;
    });
    /**
     * Retorna o estado atual do agente, composto pelas chaves
     * `input` e `output`.
     */
    get values(): {
        input: z.TypeOf<Input>;
        output: z.TypeOf<Output>;
    };
    /**
     * Tenta validar um objeto qualquer contra o schema de entrada definido.
     *
     * @param input - Dados a serem validados.
     * @returns O resultado da validação (sucesso ou erro).
     */
    parseInput(input: any): z.SafeParseReturnType<{
        [x: string]: any;
    }, {
        [x: string]: any;
    }>;
    /**
     * Tenta validar um objeto qualquer contra o schema de saída definido.
     *
     * @param output - Dados a serem validados.
     * @returns O resultado da validação (sucesso ou erro).
     */
    parseOutput(output: any): z.SafeParseReturnType<{
        [x: string]: any;
    }, {
        [x: string]: any;
    }>;
    /**
     * Atualiza o estado de entrada do agente. Ideal para ser usado após
     * a validação com `parseInput`.
     *
     * @param input - Objeto de estado de entrada que segue o schema definido.
     */
    setInput(input: z.infer<Input>): void;
    /**
     * Atualiza o estado de saída do agente. Ideal para ser usado após
     * a validação com `parseOutput`.
     *
     * @param output - Objeto de estado de saída que segue o schema definido.
     */
    setOutput(output: z.infer<Output>): void;
    /**
     * Função auxiliar que processa recursivamente objetos aninhados e arrays
     * para converter para o formato LangGraph
     *
     * @param obj - Objeto ou array a ser processado
     * @param prefix - Prefixo a ser adicionado às chaves
     * @param result - Objeto de resultado acumulado
     * @private
     */
    private static processObject;
    /**
     * Converte um objeto de estado no formato `{ input, output }`
     * para um formato de objeto plano, onde cada chave é prefixada
     * com `"input_"` ou `"output_"`.
     *
     * Este método pode ser útil para integrar com outras bibliotecas
     * que necessitem de chaves únicas (por exemplo, `LangGraph`).
     *
     * @param values - Objeto com as chaves `input` e `output`.
     * @returns Objeto plano contendo as chaves prefixadas, ex: `{ input_<key>: value, output_<key>: value }`.
     */
    static valuesToLanggraph(values: StateValuesFormat): Record<string, any>;
    /**
     * Faz o caminho inverso de `valuesToLanggraph`, ou seja, converte um
     * objeto plano (com chaves `input_...` e `output_...`) para um
     * objeto `{ input, output }`.
     *
     * @param object - Objeto contendo chaves prefixadas em `input_` e `output_`.
     * @returns Objeto `{ input, output }` reconstruído a partir das chaves lidas.
     */
    static langgraphToValues(object: Record<string, any>): {
        input: Record<string, any>;
        output: Record<string, any>;
    };
}

/**
 * Representa uma procedure do tipo "Action", cujo objetivo é **mudar** o estado do agente.
 *
 * O `ActionProcedure` faz mutações ou computações que alteram o estado de forma persistente.
 * Quando executada, retorna o objeto de estado atualizado.
 *
 * @template StateValues - Formato dos valores de estado usados pelas procedures
 * @template LLMType - Tipo específico do modelo de linguagem passado para o procedimento
 */
interface ActionProcedure<StateValues extends StateValuesFormat, LLMType extends LLMTypeBase = BaseChatModel> extends BaseProcedure {
    /**
     * Nome da próxima procedure que deve ser executada.
     *
     * Se fornecido, o fluxo de execução passa diretamente para `nextProcedure`.
     * Se não for definido, o Agent tentará executar a próxima procedure listada
     * na sequência fornecida ao `Agent`.
     * É opcional quando a lista de procedures não tiver ao menos uma procedure `check`. Quando houver,
     * é necessário indicar o nome da próxima procedure, podendo também ser `__end__`, ou a constante `END` do LangGraph.
     */
    nextProcedure?: string;
    /**
     * Método responsável por executar a ação.
     * Recebe o estado atual e o modelo de linguagem (LLM), podendo realizar alterações
     * no estado e retornando-o em seguida.
     *
     * @param state - Estado atual do agente
     * @param llm - Modelo de linguagem que o Agent utiliza para auxiliar na execução
     * @returns Estado atualizado
     */
    run(state: StateValues, llm: LLMType): Promise<StateValues>;
    /**
     * Tipo do procedimento, neste caso é sempre `"action"`
     */
    type: "action";
}
/**
 * Interface base para todas as procedures, tanto `ActionProcedure` quanto `CheckProcedure`.
 */
interface BaseProcedure {
    /**
     * Nome único para identificação da procedure
     */
    name: string;
    /**
     * Opções de tracing para a integração com o LangSmith
     */
    tracing?: {
        /**
         * Nome do procedimento a ser rastreado. Sobrescreve o nome padrão
         */
        label?: string;
        /**
         * Metadados adicionais para o procedimento. Pode ser usado para rastreamento
         * ou para fornecer informações extras sobre a execução.
         */
        metadata?: KVMap;
        /**
         * Tipo da execução procedimento a ser rastreado. Default: `"tool"`
         */
        runType?: "chain" | "embedding" | "llm" | "parser" | "prompt" | "retriever" | "tool";
    };
}
/**
 * Representa uma procedure do tipo "Check", cujo objetivo é **não alterar** o estado,
 * mas sim decidir qual será a próxima procedure.
 *
 * O `CheckProcedure` recebe o estado atual, faz uma verificação (ou análise) e
 * retorna o **nome da próxima procedure** que deve ser executada pelo {@link Agent}.
 *
 * @template StateValues - Formato dos valores de estado usados pelas procedures
 * @template LLMType - Tipo específico do modelo de linguagem passado para o procedimento
 */
interface CheckProcedure<StateValues extends StateValuesFormat, LLMType extends LLMTypeBase = BaseChatModel> extends BaseProcedure {
    /**
     * Método responsável por verificar/analisar o estado atual e retornar
     * o nome da próxima procedure a ser executada.
     *
     * @param state - Estado atual do agente
     * @param llm - Modelo de linguagem que o Agent utiliza para auxiliar na execução
     * @returns Nome da próxima procedure que o Agent deve executar, ou null/undefined para finalizar a execução
     */
    run(state: StateValues, llm: LLMType): Promise<null | string | undefined>;
    /**
     * Tipo do procedimento, neste caso é sempre `"check"`
     */
    type: "check";
}
/**
 * Tipo unificado que agrupa tanto `ActionProcedure` quanto `CheckProcedure`.
 *
 * O `Agent` irá lidar de maneira diferenciada com cada um:
 * - **Action**: Altera o estado e pode (opcionalmente*) indicar o nome da próxima procedure.
 * - **Check**: Não altera o estado e sempre retorna o nome da próxima procedure.
 *
 * @template StateValues - Formato dos valores de estado usados pelas procedures
 * @template LLMType - Tipo específico do modelo de linguagem
 */
type Procedure<StateValues extends StateValuesFormat, LLMType extends LLMTypeBase = BaseChatModel> = ActionProcedure<StateValues, LLMType> | CheckProcedure<StateValues, LLMType>;

/**
 * Tipo base que define o que um modelo de linguagem (LLM) deve ser.
 * Pode ser um BaseChatModel ou um objeto com chaves sendo os nomes dos modelos
 * e os valores sendo instâncias de BaseChatModel.
 */
type LLMTypeBase = BaseChatModel | Record<string, BaseChatModel>;
/**
 * Representa um agente de IA que processa uma sequência de {@link Procedure|Procedures}.
 *
 * A classe `Agent` é responsável por receber um estado, um conjunto de `Procedure`
 * e um modelo de linguagem (LLM), para então executar passos (Procedures) de forma
 * sequencial ou customizada (usando `nextProcedure` e/ou `CheckProcedure`). Existem dois tipos principais de `Procedure`:
 *
 * - **ActionProcedure**: Recebe e **altera** o estado do agente, realizando mutações
 *   e computações necessárias.
 * - **CheckProcedure**: Recebe o estado do agente, **não o altera**, e retorna um
 *   **nome** de próxima procedure que será executada.
 *
 * @template Input - Schema Zod para o estado de entrada
 * @template Output - Schema Zod para o estado de saída
 * @template LLMType - Tipo específico do modelo de linguagem (inferido automaticamente)
 */
declare class Agent<Input extends z.AnyZodObject, Output extends z.AnyZodObject, LLMType extends LLMTypeBase = BaseChatModel> {
    private readonly props;
    constructor(props: {
        /**
         * Modelo de linguagem que será utilizado pelas procedures. Pode ser um `ChatModel` do LangChain
         * ou um objeto mapeando nomes para modelos.
         *
         * @see {@link https://js.langchain.com/docs/concepts/chat_models} Saiba mais sobre `ChatModel` do LangChain.
         *
         * @example
         * // Modelo único
         * new ChatOpenAI()
         *
         * // Mapa de modelos
         * {
         *   "default": new ChatOpenAI(),
         *   "summarize": new ChatGoogleGenerativeAI()
         * }
         */
        llm: LLMType;
        /**
         * Opções adicionais
         */
        options?: {
            /**
             * Número máximo de iterações para evitar loops infinitos. Padrão: 100 iterações (use `Infinity` para desabilitar o limite)
             */
            maxIterations?: number;
            /**
             * Metadados adicionais para o agente. Pode ser usado para rastreamento
             * ou para fornecer informações extras sobre a cadeia de procedimentos.
             */
            metadata?: KVMap;
            /**
             * Nome do agente. Útil para depuração e rastreamento.
             */
            name?: string;
            /**
             * Se `true`, habilita logs de execução
             */
            verbose?: boolean;
        };
        /**
         * Lista de {@link Procedure} que serão executadas pelo agente
         */
        procedures: Procedure<State<Input, Output>["values"], LLMType>[];
        /**
         * Instância de {@link State} que contém os schemas de entrada/saída e o estado do agente
         */
        state: State<Input, Output>;
    });
    /**
     * Verifica se todos os nomes de procedures são únicos, lançando um erro caso haja duplicados.
     *
     * @throws {ProcedureNameError} - Se forem detectados nomes duplicados.
     * @private
     */
    private validateProcedureNames;
    /**
     * Verifica a consistência da cadeia de procedures:
     * 1. Se existe ao menos uma procedure do tipo `check`.
     * 2. Se todas as procedures do tipo `action` que fazem parte de uma cadeia
     *    com `check` declaram o `nextProcedure`.
     *
     * @throws {ProcedureChainError} - Se for detectada inconsistência na declaração de procedures.
     * @private
     */
    private validateProcedureChain;
    /**
     * Retorna o grafo do agente usando o LangGraph. Útil para casos de uso mais complexos
     * que a biblioteca não forneça suporte nativo.
     *
     * @see {@link https://langchain-ai.github.io/langgraphjs/} Saiba mais sobre o LangGraph na documentação oficial.
     *
     * @returns `StateGraph` compilado do LangGraph baseado nas procedures e no estado do agente.
     */
    get graph(): _langchain_langgraph.CompiledStateGraph<_langchain_langgraph.StateType<Record<string, any>>, _langchain_langgraph.UpdateType<Record<string, any>>, "__start__", Record<string, any>, Record<string, any>, _langchain_langgraph.StateDefinition>;
    /**
     * Executa o agente, processando as {@link Procedure|Procedures} até chegar em um fim.
     *
     * 1. Faz o parse do input inicial de acordo com o schema de entrada.
     * 2. Valida a lista e a cadeia de procedures.
     * 3. Executa cada procedure (action ou check) em loop até atingir um `END` ou o fim da lista.
     * 4. Faz o parse do output final de acordo com o schema de saída.
     *
     * @param input - Dados de entrada que seguem o schema definido em `State`.
     * @returns Dados de saída que seguem o schema definido em `State`.
     * @throws {StateValidationError} - Caso o input ou o output não siga o schema.
     * @throws {ProcedureChainError} - Caso a cadeia de procedures ultrapassar o número máximo de iterações.
     */
    run(input: z.infer<Input>): Promise<z.infer<Output>>;
}

export { type ActionProcedure, Agent, type BaseProcedure, type CheckProcedure, type InferState, type Procedure, State, type StateValuesFormat };
