"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ansi = void 0;
exports.colorize = colorize;
exports.logLine = logLine;
exports.printBanner = printBanner;
exports.printShellHelp = printShellHelp;
exports.printProfile = printProfile;
exports.printToolResult = printToolResult;
exports.printTransactionConfirmationCard = printTransactionConfirmationCard;
exports.shouldShowToolStep = shouldShowToolStep;
exports.printToolStep = printToolStep;
exports.ansi = {
    reset: "\x1b[0m",
    bold: "\x1b[1m",
    dim: "\x1b[2m",
    cyan: "\x1b[36m",
    green: "\x1b[32m",
    yellow: "\x1b[33m",
    red: "\x1b[31m",
    blue: "\x1b[34m",
    magenta: "\x1b[35m",
};
const TOOL_EVENT_MAX_CHARS = 6000;
const usdFormatter = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "USD",
    maximumFractionDigits: 2,
});
function defaultWriter(line) {
    console.log(line);
}
function writeLine(writer, line = "") {
    writer(line);
}
function writeLines(writer, lines) {
    lines.forEach((line) => writer(line));
}
function asRecord(value) {
    if (!value || typeof value !== "object" || Array.isArray(value)) {
        return null;
    }
    return value;
}
function asArray(value) {
    return Array.isArray(value) ? value : null;
}
function parseJsonIfPossible(value) {
    if (typeof value !== "string") {
        return value;
    }
    const trimmed = value.trim();
    if (trimmed.length === 0) {
        return value;
    }
    const startsLikeJson = ((trimmed.startsWith("{") && trimmed.endsWith("}")) ||
        (trimmed.startsWith("[") && trimmed.endsWith("]")));
    if (!startsLikeJson) {
        return value;
    }
    try {
        return JSON.parse(trimmed);
    }
    catch (_a) {
        return value;
    }
}
function normalizeOutput(value) {
    let current = parseJsonIfPossible(value);
    for (let depth = 0; depth < 3; depth += 1) {
        const record = asRecord(current);
        if (!record) {
            break;
        }
        const content = asArray(record.content);
        if (!content || content.length === 0) {
            break;
        }
        const first = asRecord(content[0]);
        if (!first || typeof first.text !== "string") {
            break;
        }
        const parsed = parseJsonIfPossible(first.text);
        if (parsed === current) {
            break;
        }
        current = parsed;
    }
    return current;
}
function toNumber(value) {
    if (typeof value === "number" && Number.isFinite(value)) {
        return value;
    }
    if (typeof value === "string") {
        const parsed = Number.parseFloat(value);
        if (Number.isFinite(parsed)) {
            return parsed;
        }
    }
    return undefined;
}
function formatUsd(value) {
    if (!Number.isFinite(value)) {
        return "$0.00";
    }
    return usdFormatter.format(value);
}
function shortAddress(value) {
    if (typeof value !== "string") {
        return "unknown";
    }
    const trimmed = value.trim();
    if (trimmed.length <= 14) {
        return trimmed;
    }
    return `${trimmed.slice(0, 6)}...${trimmed.slice(-4)}`;
}
function safeStringify(value) {
    if (typeof value === "string") {
        return value;
    }
    try {
        return JSON.stringify(value, null, 2);
    }
    catch (_a) {
        return String(value);
    }
}
function truncateText(text, maxChars = TOOL_EVENT_MAX_CHARS) {
    if (text.length <= maxChars) {
        return text;
    }
    const removed = text.length - maxChars;
    return `${text.slice(0, maxChars)}\n... <truncated ${removed} chars>`;
}
function indentBlock(value, prefix = "  ") {
    return value
        .split("\n")
        .map((line) => `${prefix}${line}`)
        .join("\n");
}
function summarizeBalance(step) {
    var _a;
    const input = asRecord(step.input);
    const chainId = (_a = input === null || input === void 0 ? void 0 : input.chainId) !== null && _a !== void 0 ? _a : "unknown";
    const account = shortAddress(input === null || input === void 0 ? void 0 : input.account);
    const outputRecord = asRecord(normalizeOutput(step.output));
    const lines = [
        "Action : Getting wallet balance",
        `Chain  : ${String(chainId)}`,
        `Wallet : ${account}`,
    ];
    if (!outputRecord) {
        lines.push("Result : Balance request completed.");
        return lines;
    }
    const tokens = Object.values(outputRecord)
        .map((value) => asRecord(value))
        .filter((value) => value !== null);
    if (tokens.length === 0) {
        lines.push("Result : No token balances returned.");
        return lines;
    }
    const totalUsd = tokens.reduce((sum, token) => { var _a; return sum + ((_a = toNumber(token.balanceInUsd)) !== null && _a !== void 0 ? _a : 0); }, 0);
    lines.push(`Result : ${tokens.length} tokens, total ${formatUsd(totalUsd)}`);
    const topTokens = [...tokens]
        .sort((a, b) => { var _a, _b; return ((_a = toNumber(b.balanceInUsd)) !== null && _a !== void 0 ? _a : 0) - ((_b = toNumber(a.balanceInUsd)) !== null && _b !== void 0 ? _b : 0); })
        .slice(0, 3)
        .map((token) => {
        var _a;
        const symbol = typeof token.symbol === "string" ? token.symbol : "TOKEN";
        const usd = (_a = toNumber(token.balanceInUsd)) !== null && _a !== void 0 ? _a : 0;
        return `${symbol} ${formatUsd(usd)}`;
    });
    if (topTokens.length > 0) {
        lines.push(`Top    : ${topTokens.join(", ")}`);
    }
    return lines;
}
function extractPositionRecords(value) {
    const normalized = normalizeOutput(value);
    const directArray = asArray(normalized);
    if (directArray) {
        return directArray
            .map((item) => asRecord(item))
            .filter((item) => item !== null);
    }
    const record = asRecord(normalized);
    if (!record) {
        return [];
    }
    const candidates = [];
    candidates.push(record.positions, record.data, record.result, record.items);
    const nestedData = asRecord(record.data);
    if (nestedData) {
        candidates.push(nestedData.positions, nestedData.data, nestedData.items);
    }
    for (const candidate of candidates) {
        const array = asArray(candidate);
        if (!array) {
            continue;
        }
        const records = array
            .map((item) => asRecord(item))
            .filter((item) => item !== null);
        if (records.length > 0) {
            return records;
        }
    }
    return [];
}
function getBestNumeric(record, keys) {
    for (const key of keys) {
        const value = toNumber(record[key]);
        if (typeof value === "number") {
            return value;
        }
    }
    return 0;
}
function summarizeDefiPositions(step) {
    var _a;
    const input = asRecord(step.input);
    const chain = (_a = input === null || input === void 0 ? void 0 : input.chain) !== null && _a !== void 0 ? _a : "unknown";
    const provider = typeof (input === null || input === void 0 ? void 0 : input.provider) === "string" ? input.provider : "unknown";
    const address = shortAddress(input === null || input === void 0 ? void 0 : input.address);
    const lines = [
        "Action   : Getting DeFi positions",
        `Chain    : ${String(chain)}`,
        `Wallet   : ${address}`,
        `Provider : ${provider}`,
    ];
    const positions = extractPositionRecords(step.output);
    if (positions.length === 0) {
        lines.push("Result   : No DeFi positions returned.");
        return lines;
    }
    const totalUsd = positions.reduce((sum, item) => sum + getBestNumeric(item, [
        "amountInUsd",
        "amountUSD",
        "valueUsd",
        "valueUSD",
        "balanceInUsd",
        "usdValue",
    ]), 0);
    lines.push(`Result   : ${positions.length} positions, total ${formatUsd(totalUsd)}`);
    return lines;
}
function summarizePrice(step) {
    var _a;
    const input = asRecord(step.input);
    const chainId = (_a = input === null || input === void 0 ? void 0 : input.chainId) !== null && _a !== void 0 ? _a : "unknown";
    const tokensRaw = typeof (input === null || input === void 0 ? void 0 : input.tokenAddresses) === "string"
        ? input.tokenAddresses
        : "";
    const tokenCount = tokensRaw
        .split(",")
        .map((token) => token.trim())
        .filter((token) => token.length > 0).length;
    const lines = [
        "Action : Fetching token prices",
        `Chain  : ${String(chainId)}`,
        `Tokens : ${tokenCount || "unknown"}`,
    ];
    const output = normalizeOutput(step.output);
    const record = asRecord(output);
    if (!record) {
        lines.push("Result : Price lookup completed.");
        return lines;
    }
    const firstEntry = Object.values(record)
        .map((value) => asRecord(value))
        .find((item) => item !== null);
    if (firstEntry) {
        const symbol = typeof firstEntry.symbol === "string" ? firstEntry.symbol : "TOKEN";
        const price = getBestNumeric(firstEntry, ["price", "usd", "priceUsd", "priceUSD"]);
        if (price > 0) {
            lines.push(`Sample : ${symbol} ${formatUsd(price)}`);
        }
    }
    return lines;
}
function summarizeTokenAddress(step) {
    var _a, _b, _c;
    const output = asRecord(normalizeOutput(step.output));
    const input = asRecord(step.input);
    const symbol = typeof (output === null || output === void 0 ? void 0 : output.symbol) === "string"
        ? output.symbol
        : (typeof (input === null || input === void 0 ? void 0 : input.symbol) === "string" ? input.symbol : "token");
    const chainId = (_b = (_a = output === null || output === void 0 ? void 0 : output.chainId) !== null && _a !== void 0 ? _a : input === null || input === void 0 ? void 0 : input.chainId) !== null && _b !== void 0 ? _b : "unknown";
    const address = typeof (output === null || output === void 0 ? void 0 : output.address) === "string" ? output.address : "unavailable";
    const decimals = (_c = output === null || output === void 0 ? void 0 : output.decimals) !== null && _c !== void 0 ? _c : "unknown";
    return [
        "Action   : Resolving token address",
        `Token    : ${symbol}`,
        `Chain    : ${String(chainId)}`,
        `Address  : ${address}`,
        `Decimals : ${String(decimals)}`,
    ];
}
function summarizeWebSearch(step) {
    const input = asRecord(step.input);
    const query = typeof (input === null || input === void 0 ? void 0 : input.query) === "string" ? input.query : "search query";
    const output = asRecord(normalizeOutput(step.output));
    const lines = [
        "Action : Web search",
        `Query  : ${query}`,
    ];
    const results = asArray(output === null || output === void 0 ? void 0 : output.results);
    if (results) {
        lines.push(`Result : ${results.length} sources returned.`);
    }
    const answer = typeof (output === null || output === void 0 ? void 0 : output.answer) === "string" ? output.answer.trim() : "";
    if (answer.length > 0) {
        const preview = answer.length > 140 ? `${answer.slice(0, 140)}...` : answer;
        lines.push(`Answer : ${preview}`);
    }
    return lines;
}
function summarizeRag(step) {
    const input = asRecord(step.input);
    const question = typeof (input === null || input === void 0 ? void 0 : input.question) === "string" ? input.question : "documentation query";
    const output = normalizeOutput(step.output);
    const text = safeStringify(output);
    const preview = text.length > 140 ? `${text.slice(0, 140)}...` : text;
    return [
        "Action : Searching DZap docs",
        `Query  : ${question}`,
        `Result : ${preview}`,
    ];
}
function summarizePool(step) {
    var _a;
    const input = asRecord(step.input);
    const provider = typeof (input === null || input === void 0 ? void 0 : input.provider) === "string" ? input.provider : "unknown";
    const chainId = (_a = input === null || input === void 0 ? void 0 : input.chainId) !== null && _a !== void 0 ? _a : "unknown";
    const output = normalizeOutput(step.output);
    const rows = asArray(output);
    const count = rows ? rows.length : 0;
    return [
        "Action   : Fetching pools",
        `Chain    : ${String(chainId)}`,
        `Provider : ${provider}`,
        `Result   : ${count > 0 ? `${count} pools returned.` : "Pool lookup completed."}`,
    ];
}
function summarizeChainChange(step) {
    var _a, _b;
    const input = asRecord(step.input);
    const chainId = (_b = (_a = input === null || input === void 0 ? void 0 : input.chainId) !== null && _a !== void 0 ? _a : input === null || input === void 0 ? void 0 : input.targetChainId) !== null && _b !== void 0 ? _b : "unknown";
    const message = safeStringify(normalizeOutput(step.output));
    const preview = message.length > 140 ? `${message.slice(0, 140)}...` : message;
    return [
        "Action : Chain switch flow",
        `Target : ${String(chainId)}`,
        `Result : ${preview}`,
    ];
}
function summarizeZapCallData(step) {
    var _a, _b, _c;
    const input = asRecord(step.input);
    const type = typeof (input === null || input === void 0 ? void 0 : input.type) === "string" ? input.type : "swap";
    const srcChainId = (_a = input === null || input === void 0 ? void 0 : input.srcChainId) !== null && _a !== void 0 ? _a : "unknown";
    const destChainId = (_b = input === null || input === void 0 ? void 0 : input.destChainId) !== null && _b !== void 0 ? _b : "unknown";
    const amount = (_c = input === null || input === void 0 ? void 0 : input.amount) !== null && _c !== void 0 ? _c : "unknown";
    const output = normalizeOutput(step.output);
    const outputText = safeStringify(output);
    const hasError = outputText.toLowerCase().includes("unable to retrieve route");
    return [
        "Action : Generating zap calldata",
        `Type   : ${type}`,
        `Route  : ${String(srcChainId)} -> ${String(destChainId)}`,
        `Amount : ${String(amount)}`,
        `Result : ${hasError ? "Route generation failed." : "Calldata generated and cached for execution."}`,
    ];
}
function summarizePerformZap(step) {
    const output = safeStringify(normalizeOutput(step.output));
    const approvalHashMatch = output.match(/Approval tx hash:\s*(0x[a-fA-F0-9]{16,})/);
    const zapHashMatch = output.match(/Zap tx hash:\s*(0x[a-fA-F0-9]{16,})/);
    const statusMatch = output.match(/Tx status:\s*([a-zA-Z]+)/);
    const lines = ["Action : Executing on-chain zap transaction"];
    if (approvalHashMatch) {
        lines.push(`Approve: ${approvalHashMatch[1]}`);
    }
    if (zapHashMatch) {
        lines.push(`Tx Hash: ${zapHashMatch[1]}`);
    }
    if (statusMatch) {
        lines.push(`Status : ${statusMatch[1]}`);
    }
    if (lines.length === 1) {
        const preview = output.length > 160 ? `${output.slice(0, 160)}...` : output;
        lines.push(`Result : ${preview}`);
    }
    return lines;
}
function summarizeGeneric(step) {
    const summary = step.data.trim();
    const outputPreviewRaw = safeStringify(normalizeOutput(step.output));
    const outputPreview = outputPreviewRaw.length > 180
        ? `${outputPreviewRaw.slice(0, 180)}...`
        : outputPreviewRaw;
    const lines = [
        `Action : ${summary.length > 0 && summary !== "No tool results found."
            ? summary
            : "Tool executed successfully."}`,
    ];
    if (outputPreview.trim().length > 0 && outputPreview !== "{}") {
        lines.push(`Result : ${outputPreview}`);
    }
    return lines;
}
function getMinimalToolLines(step) {
    switch (step.toolName) {
        case "BalanceTool":
            return summarizeBalance(step);
        case "DefiPositionsTool":
            return summarizeDefiPositions(step);
        case "PriceTool":
            return summarizePrice(step);
        case "TokenAddressTool":
            return summarizeTokenAddress(step);
        case "WebSearchTool":
        case "TrendingNewsTool":
        case "TrendingTokenTool":
            return summarizeWebSearch(step);
        case "RagOverDocsTool":
            return summarizeRag(step);
        case "PoolTool":
            return summarizePool(step);
        case "ZapCallDataGeneratorTool":
            return summarizeZapCallData(step);
        case "PerformZapTool":
            return summarizePerformZap(step);
        case "RequestChainChangeTool":
        case "ChangeChainTool":
            return summarizeChainChange(step);
        default:
            return summarizeGeneric(step);
    }
}
function colorize(text, color, weight = "") {
    return `${weight}${color}${text}${exports.ansi.reset}`;
}
function logLine(level, message, writer = defaultWriter) {
    switch (level) {
        case "info":
            writeLine(writer, `${colorize("[INFO]", exports.ansi.blue, exports.ansi.bold)} ${message}`);
            return;
        case "ok":
            writeLine(writer, `${colorize("[OK]", exports.ansi.green, exports.ansi.bold)} ${message}`);
            return;
        case "warn":
            writeLine(writer, `${colorize("[WARN]", exports.ansi.yellow, exports.ansi.bold)} ${message}`);
            return;
        case "error":
            writeLine(writer, `${colorize("[ERR]", exports.ansi.red, exports.ansi.bold)} ${message}`);
    }
}
function printBanner(writer = defaultWriter) {
    const lines = [
        " ____     _____                 _    ___ ",
        "|  _ \\   |__  /__ _ _ __       / \\  |_ _|",
        "| | | |____ / // _` | '_ \\     / _ \\  | | ",
        "| |_| |___// /| (_| | |_) |   / ___ \\ | | ",
        "|____/   /____|\\__,_| .__/   /_/   \\_\\___|",
        "                    |_|                    ",
    ];
    const palette = [exports.ansi.cyan, exports.ansi.blue, exports.ansi.magenta, exports.ansi.yellow, exports.ansi.green, exports.ansi.dim];
    writeLine(writer, "");
    lines.forEach((line, index) => {
        writeLine(writer, colorize(line, palette[index % palette.length], exports.ansi.bold));
    });
    writeLine(writer, colorize("Interactive DeFi assistant shell", exports.ansi.dim));
    writeLine(writer, "");
}
function printShellHelp(writer = defaultWriter) {
    const text = [
        "Slash commands:",
        "  /help                    Show this help",
        "  /tools                   List available SDK tools",
        "  /tool <Name> [JSON]      Execute one tool directly",
        "  /debug <on|off|show>     Toggle verbose internal logging",
        "  /confirmmode <on|off|show>  Toggle transaction confirmation prompts",
        "  /profile                 Show current startup profile",
        "  /set wallet <value>      Update wallet and save",
        "  /set chain <value>       Update chain and save",
        "  /set blockchain <value>  Update blockchain and save",
        "  /set privatekey <value>  Update private key and save",
        "  /session show            Show current chat session",
        "  /session new             Start a new chat session",
        "  /session history         Show current chat history",
        "  /save                    Save current profile",
        "  /init                    Re-run startup initialization",
        "  /clear                   Clear screen and redraw banner",
        "  /exit                    Exit shell",
        "",
        "Plain text input is treated as an AI prompt.",
    ];
    writeLine(writer, colorize(text.join("\n"), exports.ansi.dim));
}
function printProfile(profile, sessionId, debug, confirmTransactions, writer = defaultWriter) {
    const maskedPrivateKey = profile.privateKey.length > 12
        ? `${profile.privateKey.slice(0, 8)}...${profile.privateKey.slice(-4)}`
        : "***";
    writeLine(writer, colorize("Current profile", exports.ansi.bold));
    writeLine(writer, `  wallet:     ${profile.wallet}`);
    writeLine(writer, `  chain:      ${profile.chain}`);
    writeLine(writer, `  blockchain: ${profile.blockchain}`);
    writeLine(writer, `  privateKey: ${maskedPrivateKey}`);
    writeLine(writer, `  debug:      ${debug ? "on" : "off"}`);
    writeLine(writer, `  confirmTx:  ${confirmTransactions ? "on" : "off"}`);
    writeLine(writer, `  session:    ${sessionId !== null && sessionId !== void 0 ? sessionId : "none"}`);
}
function printToolResult(result, writer = defaultWriter) {
    const status = result.success
        ? colorize("SUCCESS", exports.ansi.green, exports.ansi.bold)
        : colorize("FAILED", exports.ansi.red, exports.ansi.bold);
    writeLine(writer, `${status} ${colorize(result.toolName, exports.ansi.magenta, exports.ansi.bold)} (${result.durationMs}ms)`);
    if (!result.success && result.error) {
        writeLine(writer, colorize(result.error, exports.ansi.red));
    }
    writeLine(writer, colorize(JSON.stringify(result.output, null, 2), exports.ansi.dim));
}
function readableAmount(value, decimals) {
    if (!value || value.trim().length === 0) {
        return "unknown";
    }
    const raw = value.trim();
    if (typeof decimals !== "number" || !Number.isInteger(decimals) || decimals < 0) {
        return raw;
    }
    if (!/^-?[0-9]+$/.test(raw)) {
        return raw;
    }
    let amount;
    try {
        amount = BigInt(raw);
    }
    catch (_a) {
        return raw;
    }
    const tokenDecimals = decimals;
    const isNegative = amount < 0n;
    const absoluteAmount = isNegative ? -amount : amount;
    if (tokenDecimals === 0) {
        return `${isNegative ? "-" : ""}${absoluteAmount.toString()}`;
    }
    const divisor = 10n ** BigInt(tokenDecimals);
    const wholePart = absoluteAmount / divisor;
    const fractionalPart = absoluteAmount % divisor;
    if (fractionalPart === 0n) {
        return `${isNegative ? "-" : ""}${wholePart.toString()}`;
    }
    const fractionalText = fractionalPart
        .toString()
        .padStart(tokenDecimals, "0")
        .replace(/0+$/, "");
    return `${isNegative ? "-" : ""}${wholePart.toString()}.${fractionalText}`;
}
function printTransactionConfirmationCard(request, writer = defaultWriter) {
    var _a, _b, _c, _d;
    const line = colorize("=".repeat(62), exports.ansi.yellow, exports.ansi.bold);
    const heading = colorize("TRANSACTION CONFIRMATION REQUIRED", exports.ansi.yellow, exports.ansi.bold);
    writeLine(writer, line);
    writeLine(writer, heading);
    writeLine(writer, line);
    writeLine(writer, colorize(`Type        : ${request.type.toUpperCase()}`, exports.ansi.dim));
    if (request.provider) {
        writeLine(writer, colorize(`Provider    : ${request.provider}`, exports.ansi.dim));
    }
    writeLine(writer, colorize(`From        : ${(_b = (_a = request.srcTokenSymbol) !== null && _a !== void 0 ? _a : request.srcTokenAddress) !== null && _b !== void 0 ? _b : "unknown"} on chain ${request.srcChainId}`, exports.ansi.dim));
    writeLine(writer, colorize(`To          : ${(_d = (_c = request.destTokenSymbol) !== null && _c !== void 0 ? _c : request.destTokenAddress) !== null && _d !== void 0 ? _d : "unknown"} on chain ${request.destChainId}`, exports.ansi.dim));
    writeLine(writer, colorize(`Amount In   : ${readableAmount(request.amountIn, request.srcTokenDecimals)}`, exports.ansi.dim));
    writeLine(writer, colorize(`Amount Out  : ${readableAmount(request.amountOut, request.destTokenDecimals)}`, exports.ansi.dim));
    writeLine(writer, colorize(`Session     : ${request.sessionId}`, exports.ansi.dim));
    writeLine(writer, line);
}
function shouldShowToolStep(step, debug) {
    var _a;
    if (debug) {
        return true;
    }
    if (step.toolName === "AI") {
        return false;
    }
    const summary = step.data.trim();
    const hasNoData = summary.length === 0 || summary === "No tool results found.";
    const noInput = Object.keys((_a = step.input) !== null && _a !== void 0 ? _a : {}).length === 0;
    const outputText = safeStringify(step.output).trim();
    const noOutput = outputText.length === 0 || outputText === "{}" || outputText === "null";
    return !(hasNoData && noInput && noOutput);
}
function printToolStep(step, index, options, writer = defaultWriter) {
    const title = `[TOOL ${index}] ${step.toolName}`;
    writeLine(writer, colorize(title, exports.ansi.magenta, exports.ansi.bold));
    if (options.debug) {
        if (step.data.trim().length > 0) {
            writeLine(writer, `${colorize("Summary:", exports.ansi.blue, exports.ansi.bold)} ${step.data.trim()}`);
        }
        const inputText = truncateText(safeStringify(step.input));
        const outputText = truncateText(safeStringify(step.output));
        writeLine(writer, colorize("Input:", exports.ansi.cyan, exports.ansi.bold));
        writeLine(writer, colorize(indentBlock(inputText), exports.ansi.dim));
        writeLine(writer, colorize("Output:", exports.ansi.green, exports.ansi.bold));
        writeLine(writer, colorize(indentBlock(outputText), exports.ansi.dim));
        writeLine(writer, "");
        return;
    }
    const lines = getMinimalToolLines(step);
    writeLines(writer, lines.map((line) => colorize(`  ${line}`, exports.ansi.dim)));
    writeLine(writer, "");
}
