"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DZapSDK = void 0;
const node_fs_1 = __importDefault(require("node:fs"));
const node_assert_1 = __importDefault(require("node:assert"));
const ToolFormatter_1 = require("../formatter/ToolFormatter");
const Setup_1 = require("../helper/Setup");
const Memory_1 = require("../memory/Memory");
const MessageType_1 = require("../memory/MessageType");
const logger_1 = require("../logger/logger");
const retrieve_1 = require("../Embedding/retrieve");
const scheduler_1 = require("../Sheluder/scheduler");
const db_1 = require("../Sheluder/db");
const zapRegistry_1 = require("../tools/goatTools/zapRegistry");
const chainChangeRegistry_1 = require("../tools/goatTools/chainChangeRegistry");
const SDKToolsRegistry_1 = require("../tools/sdktools/SDKToolsRegistry");
const staticPath_1 = require("../utils/staticPath");
const CLIAgent_1 = require("../agents/CLIAgent");
const startupPassword_1 = require("../security/startupPassword");
class DZapSDK {
    constructor(options = {}) {
        this.agent = null;
        this.unlocked = false;
        this.toolFormatter = new ToolFormatter_1.ToolFormatter();
        this.memory = new Memory_1.Memory();
        this.setup = new Setup_1.Setup(options.baseUrl);
        this.tools = new SDKToolsRegistry_1.SDKToolsRegistry();
        this.systemPrompt = this.loadSystemPrompt(options.systemPrompt, options.systemPromptPath);
    }
    async initialize(options = {}) {
        var _a, _b;
        if (!this.unlocked) {
            this.unlock((_b = (_a = options.startupPassword) !== null && _a !== void 0 ? _a : process.env.DZAP_STARTUP_PASSWORD) !== null && _b !== void 0 ? _b : "");
        }
        if (options.syncProviders) {
            const providers = await this.setup.loadProviderList();
            logger_1.logger.info(`[Setup] Synced ${Object.keys(providers).length} DeFi providers.`);
        }
        if (options.initializeRetrieval) {
            await (0, retrieve_1.initRetrieval)();
        }
    }
    unlock(password) {
        if (this.unlocked) {
            return;
        }
        if (!(0, startupPassword_1.isValidStartupPassword)(password)) {
            throw new Error("Invalid startup password.");
        }
        this.unlocked = true;
    }
    async ask(input) {
        var _a, _b, _c, _d;
        this.assertUnlocked();
        const { userQuery, metadata, sessionId, onStep, transactionConfirmationMode, onTransactionConfirmation, } = input;
        this.validateMetadata(metadata);
        if (userQuery.trim().length === 0) {
            throw new Error("userQuery must be a non-empty string.");
        }
        const metadataForPrompt = this.sanitizeMetadataForPrompt(metadata);
        const metadataString = JSON.stringify(metadataForPrompt);
        const promptWithWallets = `${userQuery.trim()} ...........  Connected Wallets : ${metadataString}`;
        let normalizedSessionId = sessionId === null || sessionId === void 0 ? void 0 : sessionId.trim();
        if ((normalizedSessionId === null || normalizedSessionId === void 0 ? void 0 : normalizedSessionId.length) === 0) {
            normalizedSessionId = undefined;
        }
        const activeSessionId = this.memory.addChatHistory(promptWithWallets, MessageType_1.MessageType.USER, normalizedSessionId);
        const sessionLogger = (0, logger_1.createSessionLogger)(activeSessionId);
        const chainIdFromMetadata = metadata.accountInfo[0].chain;
        const privateKey = (_b = (_a = metadata.accountInfo[0]) === null || _a === void 0 ? void 0 : _a.private_key) === null || _b === void 0 ? void 0 : _b.trim();
        if (privateKey) {
            (0, zapRegistry_1.saveSessionPrivateKey)(activeSessionId, privateKey);
        }
        (0, zapRegistry_1.setSessionTransactionConfirmationMode)(activeSessionId, transactionConfirmationMode === "on");
        (0, zapRegistry_1.setSessionTransactionConfirmationHandler)(activeSessionId, onTransactionConfirmation);
        (0, logger_1.setSessionMetadata)(activeSessionId, {
            route: "sdk.ask",
            chain: chainIdFromMetadata,
            user_account: (_d = (_c = metadata.accountInfo[0]) === null || _c === void 0 ? void 0 : _c.user_account) !== null && _d !== void 0 ? _d : null,
            wallet_count: metadata.accountInfo.length,
        });
        (0, logger_1.recordConversation)(activeSessionId, MessageType_1.MessageType.USER, promptWithWallets, {
            chain: chainIdFromMetadata,
        });
        const messageHistory = this.memory.getChatHistory(activeSessionId).getHistory();
        if (messageHistory.length === 0 || messageHistory[0].role !== "system") {
            messageHistory.unshift({
                role: "system",
                content: `${this.systemPrompt}\n${this.systemPrompt}`,
            });
        }
        let balanceData;
        let chainId = chainIdFromMetadata;
        const steps = [];
        const finalText = await this.getAgent().processPromptStream(messageHistory, this.systemPrompt, (step) => {
            var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
            if (!Array.isArray(step === null || step === void 0 ? void 0 : step.toolResults) || step.toolResults.length === 0) {
                return;
            }
            const toolResponse = this.toolFormatter.formatText(step, "prod");
            const toolName = (_c = (_b = (_a = step === null || step === void 0 ? void 0 : step.toolResults) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.toolName) !== null && _c !== void 0 ? _c : "AI";
            if (toolName === "BalanceTool" && ((_f = (_e = (_d = step.toolCalls) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.input) === null || _f === void 0 ? void 0 : _f.for_user)) {
                balanceData = (_h = (_g = step.toolResults) === null || _g === void 0 ? void 0 : _g[0]) === null || _h === void 0 ? void 0 : _h.output;
                chainId = (_m = (_l = (_k = (_j = step.toolCalls) === null || _j === void 0 ? void 0 : _j[0]) === null || _k === void 0 ? void 0 : _k.input) === null || _l === void 0 ? void 0 : _l.chainId) !== null && _m !== void 0 ? _m : chainId;
            }
            const stepEvent = {
                sessionId: activeSessionId,
                toolName,
                data: toolResponse.formatString,
                input: toolResponse.input,
                output: toolResponse.output,
            };
            steps.push(stepEvent);
            onStep === null || onStep === void 0 ? void 0 : onStep(stepEvent);
            sessionLogger.info("Tool step completed", {
                tool_name: toolName,
                tool_calls_count: Array.isArray(step.toolCalls) ? step.toolCalls.length : 0,
                tool_results_count: Array.isArray(step.toolResults) ? step.toolResults.length : 0,
                input: toolResponse.input,
                output: toolResponse.output,
            });
        });
        this.memory.addChatHistory(finalText, MessageType_1.MessageType.ASSISTANT, activeSessionId);
        (0, logger_1.recordConversation)(activeSessionId, MessageType_1.MessageType.ASSISTANT, finalText, {
            chain_id: chainId,
            balance_ui: Boolean(balanceData),
        });
        sessionLogger.info("Completed sdk.ask response", {
            response_length: finalText.length,
            balance_ui: Boolean(balanceData),
        });
        return {
            sessionId: activeSessionId,
            finalText,
            chainId,
            balanceData,
            steps,
        };
    }
    getChatHistory(sessionId) {
        this.assertUnlocked();
        const history = this.memory.getChatHistory(sessionId.trim()).getHistory();
        return history.map((message) => ({
            role: message.role,
            content: message.content,
        }));
    }
    listTools() {
        this.assertUnlocked();
        return this.tools.listTools();
    }
    getTool(name) {
        this.assertUnlocked();
        return this.tools.getToolByName(name);
    }
    async executeTool(name, input) {
        this.assertUnlocked();
        return this.tools.executeToolByName(name, input);
    }
    getSessionHistory(sessionId) {
        this.assertUnlocked();
        return (0, logger_1.getSessionSnapshot)(sessionId.trim());
    }
    getSchedulesByUserId(userId) {
        this.assertUnlocked();
        return (0, db_1.getScheduleByUserId)(userId);
    }
    confirmZap(sessionId, message) {
        this.assertUnlocked();
        return (0, zapRegistry_1.resolveZap)(sessionId, message);
    }
    confirmChainChange(sessionId, message) {
        this.assertUnlocked();
        return (0, chainChangeRegistry_1.resolveChainChange)(sessionId, message);
    }
    async runSchedulerOnce() {
        this.assertUnlocked();
        await (0, scheduler_1.runScheduler)();
    }
    startSchedulerLoop(intervalMs = 60 * 1000) {
        this.assertUnlocked();
        return setInterval(async () => {
            var _a;
            try {
                logger_1.logger.info(`[Scheduler] Running at ${new Date().toISOString()}`);
                await (0, scheduler_1.runScheduler)();
            }
            catch (error) {
                logger_1.logger.error("[Scheduler] Failed", {
                    error: error instanceof Error ? (_a = error.stack) !== null && _a !== void 0 ? _a : error.message : String(error),
                });
            }
        }, intervalMs);
    }
    loadSystemPrompt(inlinePrompt, promptPath) {
        if (typeof inlinePrompt === "string" && inlinePrompt.trim().length > 0) {
            return inlinePrompt;
        }
        const resolvedPath = promptPath !== null && promptPath !== void 0 ? promptPath : (0, staticPath_1.resolveStaticFilePath)("ZapGPTPrompt.txt");
        const prompt = node_fs_1.default.readFileSync(resolvedPath, "utf-8");
        node_assert_1.default.ok(prompt.length > 0, "System prompt is empty");
        return prompt;
    }
    assertUnlocked() {
        if (!this.unlocked) {
            throw new Error("SDK is locked. Call initialize with the correct startup password first.");
        }
    }
    validateMetadata(metadata) {
        if (!metadata || !Array.isArray(metadata.accountInfo) || metadata.accountInfo.length === 0) {
            throw new Error("metadata.accountInfo must be a non-empty array.");
        }
    }
    sanitizeMetadataForPrompt(metadata) {
        return {
            accountInfo: metadata.accountInfo.map((account) => ({
                blockchain: account.blockchain,
                chain: account.chain,
                user_account: account.user_account,
            })),
        };
    }
    getAgent() {
        if (!this.agent) {
            this.agent = new CLIAgent_1.CLIAgent();
        }
        return this.agent;
    }
}
exports.DZapSDK = DZapSDK;
