import { ApiError, } from "./types";
/**
 * Abstract client class for interacting with the Axiom Lattice Agent Service API
 * Provides common functionality for different client implementations
 */
export class AbstractClient {
    /**
     * Creates a new AbstractClient instance
     * @param config - Configuration options for the client
     */
    constructor(config) {
        this.tenantId = "";
        this.registeredTools = new Map();
        /**
         * Chat namespace for sending messages and streaming responses
         */
        this.chat = {
            /**
             * Sends a message to a thread and receives a response
             * @param options - Options for sending a message
             * @returns A promise that resolves to the chat response
             */
            send: async (options) => {
                try {
                    // Extract the message from the messages array (assuming the last message is the one to send)
                    const message = options.messages[options.messages.length - 1];
                    const { command, threadId, files, assistantId, ...rest } = options;
                    // Use the run method to send the message
                    const result = await this.run({
                        threadId: threadId,
                        message: typeof message.content === "string"
                            ? message.content
                            : JSON.stringify(message.content),
                        streaming: false,
                        command: command,
                        files: files,
                        ...rest,
                    });
                    return result;
                }
                catch (error) {
                    throw error;
                }
            },
            /**
             * Sends a message to a thread and streams the response
             * @param options - Options for streaming a message
             * @param onEvent - Callback function that receives stream events
             * @param onComplete - Optional callback function called when streaming completes
             * @param onError - Optional callback function called when an error occurs
             * @returns A function that can be called to stop the stream
             */
            stream: (options, onEvent, onComplete, onError) => {
                const { command, threadId, files, assistantId, background, enableReturnStateWhenSteamCompleted, ...rest } = options;
                // Extract the message from the messages array (assuming the last message is the one to send)
                const message = options.messages[options.messages.length - 1];
                // Use the streamRequest method to stream the response
                return this.streamRequest({
                    threadId: threadId,
                    assistantId: assistantId,
                    message: typeof message.content === "string"
                        ? message.content
                        : JSON.stringify(message.content),
                    streaming: true,
                    command: command,
                    background: background,
                    enableReturnStateWhenSteamCompleted: enableReturnStateWhenSteamCompleted,
                    ...rest,
                }, onEvent, onComplete, onError);
            },
        };
        /**
         * Tools namespace for registering and unregistering client-side tools
         */
        this.tools = {
            /**
             * Registers a client-side tool
             * @param options - Options for registering a tool
             */
            register: (options) => {
                if (this.config.transport !== "ws") {
                    throw new Error("Client-side tools are only supported with WebSocket transport");
                }
                this.registeredTools.set(options.name, options);
            },
            /**
             * Unregisters a client-side tool
             * @param name - Tool name
             */
            unregister: (name) => {
                this.registeredTools.delete(name);
            },
        };
        /**
         * Assistants namespace for managing assistants
         */
        this.assistants = {
            /**
             * Lists all available assistants
             * Returns both code-configured and stored assistants
             * @returns A promise that resolves to the list of assistants
             */
            list: async () => {
                try {
                    const response = await this.makeRequest("/api/assistants");
                    return response.data.records;
                }
                catch (error) {
                    throw error;
                }
            },
            /**
             * Retrieves a single assistant by ID
             * Checks both code-configured and stored assistants
             * @param id - Assistant identifier
             * @returns A promise that resolves to the assistant information
             */
            get: async (id) => {
                try {
                    const response = await this.makeRequest(`/api/assistants/${id}`);
                    if (!response.data) {
                        throw new ApiError("Assistant not found", 404);
                    }
                    return response.data;
                }
                catch (error) {
                    throw error;
                }
            },
            /**
             * Creates a new assistant
             * Only creates stored assistants (code-configured assistants cannot be created via API)
             * @param options - Options for creating an assistant
             * @returns A promise that resolves to the created assistant
             */
            create: async (options) => {
                try {
                    const response = await this.makeRequest("/api/assistants", {
                        method: "POST",
                        body: options,
                    });
                    if (!response.data) {
                        throw new ApiError("Failed to create assistant", 500);
                    }
                    return response.data;
                }
                catch (error) {
                    throw error;
                }
            },
            /**
             * Updates an existing assistant by ID
             * Only works on stored assistants (code-configured assistants cannot be updated)
             * @param id - Assistant identifier
             * @param options - Options for updating an assistant
             * @returns A promise that resolves to the updated assistant
             */
            update: async (id, options) => {
                try {
                    const response = await this.makeRequest(`/api/assistants/${id}`, {
                        method: "PUT",
                        body: options,
                    });
                    if (!response.data) {
                        throw new ApiError("Failed to update assistant", 500);
                    }
                    return response.data;
                }
                catch (error) {
                    throw error;
                }
            },
            /**
             * Deletes an assistant by ID
             * Only works on stored assistants (code-configured assistants cannot be deleted)
             * @param id - Assistant identifier
             * @returns A promise that resolves when the assistant is deleted
             */
            delete: async (id) => {
                try {
                    await this.makeRequest(`/api/assistants/${id}`, {
                        method: "DELETE",
                    });
                }
                catch (error) {
                    throw error;
                }
            },
        };
        /**
         * Threads namespace for managing threads for the current assistant
         */
        this.threads = {
            /**
             * Lists all threads for the current assistant
             * @returns A promise that resolves to the list of threads
             */
            list: async () => {
                try {
                    const response = await this.makeRequest(`/api/assistants/${this.assistantId}/threads`);
                    return response.data.records;
                }
                catch (error) {
                    throw error;
                }
            },
            /**
             * Retrieves a single thread by ID for the current assistant
             * @param threadId - Thread identifier
             * @returns A promise that resolves to the thread information
             */
            get: async (threadId) => {
                try {
                    const response = await this.makeRequest(`/api/assistants/${this.assistantId}/threads/${threadId}`);
                    if (!response.data) {
                        throw new ApiError("Thread not found", 404);
                    }
                    return response.data;
                }
                catch (error) {
                    throw error;
                }
            },
            /**
             * Creates a new thread for the current assistant
             * @param options - Options for creating a thread
             * @returns A promise that resolves to the created thread
             */
            create: async (options) => {
                try {
                    const response = await this.makeRequest(`/api/assistants/${this.assistantId}/threads`, {
                        method: "POST",
                        body: options,
                    });
                    if (!response.data) {
                        throw new ApiError("Failed to create thread", 500);
                    }
                    return response.data;
                }
                catch (error) {
                    throw error;
                }
            },
            /**
             * Updates an existing thread by ID for the current assistant
             * @param threadId - Thread identifier
             * @param options - Options for updating a thread
             * @returns A promise that resolves to the updated thread
             */
            update: async (threadId, options) => {
                try {
                    const response = await this.makeRequest(`/api/assistants/${this.assistantId}/threads/${threadId}`, {
                        method: "PUT",
                        body: options,
                    });
                    if (!response.data) {
                        throw new ApiError("Failed to update thread", 500);
                    }
                    return response.data;
                }
                catch (error) {
                    throw error;
                }
            },
            /**
             * Deletes a thread by ID for the current assistant
             * @param threadId - Thread identifier
             * @returns A promise that resolves when the thread is deleted
             */
            delete: async (threadId) => {
                try {
                    await this.makeRequest(`/api/assistants/${this.assistantId}/threads/${threadId}`, {
                        method: "DELETE",
                    });
                }
                catch (error) {
                    throw error;
                }
            },
        };
        /**
         * Schedules namespace for managing scheduled tasks
         */
        this.schedules = {
            /**
             * Gets scheduled tasks for a specific thread
             * @param options - Options for getting scheduled tasks
             * @returns A promise that resolves to the list of scheduled tasks
             */
            getByThread: async (options) => {
                try {
                    let url = `/api/assistants/${this.assistantId}/threads/${options.threadId}/schedules`;
                    const params = new URLSearchParams();
                    if (options.status) {
                        params.append("status", options.status);
                    }
                    if (options.limit !== undefined) {
                        params.append("limit", options.limit.toString());
                    }
                    if (options.offset !== undefined) {
                        params.append("offset", options.offset.toString());
                    }
                    const queryString = params.toString();
                    if (queryString) {
                        url += `?${queryString}`;
                    }
                    const response = await this.makeRequest(url);
                    return response.data.records;
                }
                catch (error) {
                    throw error;
                }
            },
            /**
             * Gets a single scheduled task by ID
             * @param taskId - Task identifier
             * @returns A promise that resolves to the scheduled task or null
             */
            get: async (taskId) => {
                try {
                    const response = await this.makeRequest(`/api/schedules/${taskId}`);
                    return response.data;
                }
                catch (error) {
                    throw error;
                }
            },
            /**
             * Cancels a scheduled task
             * @param taskId - Task identifier
             * @returns A promise that resolves when the task is cancelled
             */
            cancel: async (taskId) => {
                try {
                    const response = await this.makeRequest(`/api/schedules/${taskId}/cancel`, {
                        method: "POST",
                    });
                    return response.success;
                }
                catch (error) {
                    throw error;
                }
            },
            /**
             * Pauses a scheduled cron task
             * @param taskId - Task identifier
             * @returns A promise that resolves when the task is paused
             */
            pause: async (taskId) => {
                try {
                    const response = await this.makeRequest(`/api/schedules/${taskId}/pause`, {
                        method: "POST",
                    });
                    return response.success;
                }
                catch (error) {
                    throw error;
                }
            },
            /**
             * Resumes a paused cron task
             * @param taskId - Task identifier
             * @returns A promise that resolves when the task is resumed
             */
            resume: async (taskId) => {
                try {
                    const response = await this.makeRequest(`/api/schedules/${taskId}/resume`, {
                        method: "POST",
                    });
                    return response.success;
                }
                catch (error) {
                    throw error;
                }
            },
        };
        this.config = {
            timeout: 300000, // Default timeout
            ...config,
        };
        this.assistantId = config.assistantId;
    }
    /**
     * Set assistant ID for the client
     * @param assistantId - Assistant identifier
     */
    setAssistantId(assistantId) {
        this.assistantId = assistantId;
    }
    /**
     * Creates a clone of the current client instance
     * @param overrides - Optional configuration overrides for the cloned client
     * @returns A new client instance with the same configuration and state
     */
    clone(overrides) {
        // Clone the config with current state
        const clonedConfig = {
            ...this.config,
            assistantId: this.assistantId,
            ...overrides,
        };
        // Create a new client instance using the abstract method
        const clonedClient = this.createInstance(clonedConfig);
        // Copy tenant ID if set
        if (this.tenantId) {
            clonedClient.setTenantId(this.tenantId);
        }
        // Copy registered tools
        this.registeredTools.forEach((tool, name) => {
            clonedClient.registeredTools.set(name, tool);
        });
        return clonedClient;
    }
    /**
     * Abstract method for streaming API requests
     * To be implemented by concrete client classes
     */
    /**
     * Helper method to build stream request parameters
     * @param options - Options for running the agent
     * @returns The formatted request parameters
     */
    buildStreamRequestParams(options) {
        const { command, threadId, message, files, background, ...rest } = options;
        return {
            url: "/api/runs",
            method: "POST",
            body: {
                assistant_id: this.assistantId,
                thread_id: threadId,
                message: message,
                files: files,
                command: command,
                streaming: true,
                background: background || false,
                ...rest,
            },
        };
    }
    /**
     * Creates a new thread
     * @deprecated Use threads.create() instead
     * @param options - Options for creating a thread
     * @returns A promise that resolves to the thread ID
     */
    async createThread(options) {
        try {
            const response = await this.makeRequest(`/api/assistants/${this.assistantId}/threads`, {
                method: "POST",
                body: options,
            });
            if (!response.data) {
                throw new ApiError("Failed to create thread", 500);
            }
            return response.data.id;
        }
        catch (error) {
            throw error;
        }
    }
    /**
     * Retrieves thread information
     * @deprecated Use threads.get() instead
     * @param threadId - Thread identifier
     * @returns A promise that resolves to the thread information
     */
    async getThread(threadId) {
        try {
            const response = await this.makeRequest(`/api/assistants/${this.assistantId}/threads/${threadId}`);
            if (!response.data) {
                throw new ApiError("Thread not found", 404);
            }
            return response.data;
        }
        catch (error) {
            throw error;
        }
    }
    /**
     * Lists all threads
     * @deprecated Use threads.list() instead
     * @param options - Options for listing threads
     * @returns A promise that resolves to an array of threads
     */
    async listThreads(options) {
        try {
            const response = await this.makeRequest(`/api/assistants/${this.assistantId}/threads`);
            return response.data.records;
        }
        catch (error) {
            throw error;
        }
    }
    /**
     * Deletes a thread
     * @deprecated Use threads.delete() instead
     * @param threadId - Thread identifier
     * @returns A promise that resolves when the thread is deleted
     */
    async deleteThread(threadId) {
        try {
            await this.makeRequest(`/api/assistants/${this.assistantId}/threads/${threadId}`, { method: "DELETE" });
        }
        catch (error) {
            throw error;
        }
    }
    /**
     * Retrieves messages from a thread
     * @param options - Options for retrieving messages
     * @returns A promise that resolves to an array of messages
     */
    async getMessages(options) {
        try {
            let url = `/api/assistants/${this.assistantId}/${options.threadId}/memory`;
            if (options.limit) {
                url += `?limit=${options.limit}`;
            }
            if (options.after) {
                url += url.includes("?")
                    ? `&after=${options.after}`
                    : `?after=${options.after}`;
            }
            if (options.reverse !== undefined) {
                url += url.includes("?")
                    ? `&reverse=${options.reverse}`
                    : `?reverse=${options.reverse}`;
            }
            url += url.includes("?")
                ? `&assistantId=${this.assistantId}`
                : `?assistantId=${this.assistantId}`;
            return await this.makeRequest(url);
        }
        catch (error) {
            throw error;
        }
    }
    /**
     * Retrieves agent state
     * @param threadId - Thread identifier
     * @returns A promise that resolves to the agent state
     */
    async getAgentState(threadId) {
        try {
            return await this.makeRequest(`/api/assistants/${this.assistantId}/${threadId}/state`);
        }
        catch (error) {
            throw error;
        }
    }
    /**
     * Gets agent graph visualization
     * @returns A promise that resolves to the graph visualization data
     */
    async getAgentGraph() {
        try {
            const data = await this.makeRequest(`/api/assistants/${this.assistantId}/graph`);
            return data.image;
        }
        catch (error) {
            throw error;
        }
    }
    /**
     * Run agent with options
     * @param options - Options for running the agent
     * @returns A promise that resolves to the run result
     */
    async run(options) {
        try {
            const { command, threadId, assistantId, message, files, background, ...rest } = options;
            if (options.streaming) {
                throw new Error("Streaming without callbacks is not supported. Use chat.stream with callbacks instead.");
            }
            else {
                return await this.makeRequest("/api/runs", {
                    method: "POST",
                    body: {
                        assistant_id: assistantId || this.assistantId,
                        thread_id: threadId,
                        message: message,
                        files: files,
                        command: command,
                        streaming: false,
                        background: background || false,
                        ...rest,
                    },
                });
            }
        }
        catch (error) {
            throw error;
        }
    }
}
//# sourceMappingURL=abstract-client.js.map