"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.decodeTokenAccountAmount = decodeTokenAccountAmount;
exports.extractTokenAccountMintBytes = extractTokenAccountMintBytes;
exports.buildTokenBalanceFilters = buildTokenBalanceFilters;
exports.listenToTokenBalanceChanges = listenToTokenBalanceChanges;
exports.listenToNativeSolBalance = listenToNativeSolBalance;
const accountSubscriptionManager_1 = require("./accountSubscriptionManager");
const utils_1 = require("./utils");
/** Decode u64 amount from SPL Token account data at byte offset 64 */
function decodeTokenAccountAmount(data) {
    const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
    return view.getBigUint64(64, true);
}
/** Extract the 32-byte mint from SPL Token account data (offset 0-32) */
function extractTokenAccountMintBytes(data) {
    return data.slice(0, 32);
}
/**
 * Build WS subscription filters for token accounts owned by a wallet.
 *
 * Uses only owner memcmp (no dataSize) so it matches both standard Token Program
 * accounts (165 bytes) and Token-2022 accounts with extensions (variable size).
 * The owner field is at offset 32 in both layouts.
 */
function buildTokenBalanceFilters(owner) {
    return [{ memcmp: { offset: 32n, bytes: owner.toString(), encoding: 'base58' } }];
}
/**
 * Subscribe to all token account balance changes for a given owner on
 * a specific token program. Routes through AccountSubscriptionManager
 * for slot-ordering, buffer dedup, and ref-counting.
 *
 * Returns an unsubscribe function.
 *
 * TODO: Monitor if programSubscribe on Token Program causes connection
 * instability due to high server-side write volume. If so, consumers
 * should fall back to per-ATA accountSubscribe.
 */
function listenToTokenBalanceChanges(params) {
    const filters = buildTokenBalanceFilters(params.owner);
    return params.manager.subscribeProgramAccounts(params.tokenProgramId, filters, (ataAddress, buffer) => {
        try {
            params.onBalanceChange({
                ataAddress,
                amount: decodeTokenAccountAmount(buffer),
                mintBytes: extractTokenAccountMintBytes(buffer),
            });
        }
        catch (e) {
            params.onError?.(e);
        }
    }, { commitment: 'confirmed' });
}
/**
 * Subscribe to native SOL balance changes for a wallet.
 * Returns an unsubscribe function.
 *
 * Uses its own WS loop because AccountSubscriptionManager only supports
 * programNotifications, and native SOL requires accountNotifications.
 */
function listenToNativeSolBalance(params) {
    const reconnectDelayMs = params.reconnectDelayMs ?? accountSubscriptionManager_1.WS_RECONNECT_DELAY_MS;
    const abortController = new AbortController();
    (async () => {
        while (!abortController.signal.aborted) {
            try {
                const notifications = await params.wsRpc
                    .accountNotifications(params.owner, { commitment: 'confirmed', encoding: 'base64' })
                    .subscribe({ abortSignal: abortController.signal });
                for await (const notification of notifications) {
                    try {
                        params.onBalanceChange({ lamports: notification.value.lamports });
                    }
                    catch (e) {
                        params.onError?.(e);
                    }
                }
            }
            catch (e) {
                if (abortController.signal.aborted)
                    break;
                params.onError?.(e);
                await (0, utils_1.sleep)(reconnectDelayMs);
            }
        }
    })();
    return () => abortController.abort();
}
//# sourceMappingURL=balanceListener.js.map