"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
    for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.RequestError = exports.ErrorCodes = exports.amount_max = void 0;
exports.createClient = createClient;
exports.id = id;
__exportStar(require("./bindings"), exports);
const bindings_1 = require("./bindings");
const node_crypto_1 = require("node:crypto");
const binding = (() => {
    const { arch, platform } = process;
    const archMap = {
        "arm64": "aarch64",
        "x64": "x86_64"
    };
    const platformMap = {
        "linux": "linux",
        "darwin": "macos",
        "win32": "windows",
    };
    if (!(arch in archMap)) {
        throw new Error(`Unsupported arch: ${arch}`);
    }
    if (!(platform in platformMap)) {
        throw new Error(`Unsupported platform: ${platform}`);
    }
    let linuxABI = '';
    if (platform === 'linux') {
        const glibcVersionRuntime = process.report.getReport().header.glibcVersionRuntime;
        if (glibcVersionRuntime) {
            linuxABI = '-gnu';
        }
        else {
            linuxABI = '-musl';
        }
    }
    const filename = `./bin/${archMap[arch]}-` +
        `${platformMap[platform]}${linuxABI}/client.node`;
    return require(filename);
})();
exports.amount_max = (2n ** 128n) - 1n;
exports.ErrorCodes = {
    ERR_CLIENT_CLOSED: 'ERR_CLIENT_CLOSED',
    ERR_CLIENT_EVICTED: 'ERR_CLIENT_EVICTED',
    ERR_CLIENT_RELEASE_TOO_LOW: 'ERR_CLIENT_RELEASE_TOO_LOW',
    ERR_CLIENT_RELEASE_TOO_HIGH: 'ERR_CLIENT_RELEASE_TOO_HIGH',
    ERR_TOO_MUCH_DATA: 'ERR_TOO_MUCH_DATA',
};
class RequestError extends Error {
    constructor(code) {
        super(RequestError.errorMessage(code));
        this.name = 'RequestError';
        this.code = code;
    }
    static errorMessage(code) {
        switch (code) {
            case exports.ErrorCodes.ERR_CLIENT_CLOSED:
                return 'Client was closed.';
            case exports.ErrorCodes.ERR_CLIENT_EVICTED:
                return 'Client was evicted.';
            case exports.ErrorCodes.ERR_CLIENT_RELEASE_TOO_LOW:
                return 'Client was evicted: release too old.';
            case exports.ErrorCodes.ERR_CLIENT_RELEASE_TOO_HIGH:
                return 'Client was evicted: release too new.';
            case exports.ErrorCodes.ERR_TOO_MUCH_DATA:
                return 'Too much data was sent or requested in this batch.';
            default:
                throw new Error("Unknown error code.");
        }
    }
}
exports.RequestError = RequestError;
function createClient(args) {
    let context = binding.init({
        cluster_id: args.cluster_id,
        replica_addresses: Buffer.from(args.replica_addresses.join(',')),
        request_error_class: RequestError,
    });
    const destroy = () => {
        if (context)
            binding.deinit(context);
        context = null;
    };
    const request = (operation, batch) => {
        return new Promise((resolve, reject) => {
            try {
                if (!context)
                    throw new RequestError(exports.ErrorCodes.ERR_CLIENT_CLOSED);
                binding.submit(context, operation, batch, (error, result) => {
                    if (error) {
                        reject(error);
                    }
                    else if (result) {
                        resolve(result);
                    }
                    else {
                        throw new Error("UB: Binding invoked callback without error or result");
                    }
                });
            }
            catch (err) {
                reject(err);
            }
        });
    };
    return {
        createAccounts(batch) { return request(bindings_1.Operation.create_accounts, batch); },
        createTransfers(batch) { return request(bindings_1.Operation.create_transfers, batch); },
        lookupAccounts(batch) { return request(bindings_1.Operation.lookup_accounts, batch); },
        lookupTransfers(batch) { return request(bindings_1.Operation.lookup_transfers, batch); },
        getAccountTransfers(filter) { return request(bindings_1.Operation.get_account_transfers, [filter]); },
        getAccountBalances(filter) { return request(bindings_1.Operation.get_account_balances, [filter]); },
        queryAccounts(filter) { return request(bindings_1.Operation.query_accounts, [filter]); },
        queryTransfers(filter) { return request(bindings_1.Operation.query_transfers, [filter]); },
        destroy,
    };
}
let idLastTimestamp = 0;
const idLastBuffer = new DataView(new ArrayBuffer(16));
const idLastBufferArray = new Uint8Array(idLastBuffer.buffer, idLastBuffer.byteOffset, idLastBuffer.byteLength);
function id() {
    let timestamp = Date.now();
    if (timestamp <= idLastTimestamp) {
        timestamp = idLastTimestamp;
    }
    else {
        idLastTimestamp = timestamp;
        (0, node_crypto_1.randomFillSync)(idLastBufferArray);
    }
    const littleEndian = true;
    const randomLo32 = idLastBuffer.getUint32(0, littleEndian) + 1;
    const randomHi32 = idLastBuffer.getUint32(4, littleEndian) + (randomLo32 > 4294967295 ? 1 : 0);
    const randomHi16 = idLastBuffer.getUint16(8, littleEndian) + (randomHi32 > 4294967295 ? 1 : 0);
    if (randomHi16 > 0xFFFF) {
        timestamp += 1;
        idLastTimestamp = timestamp;
        if (timestamp === 281474976710656) {
            throw new Error('timestamp overflow on monotonic increment');
        }
    }
    idLastBuffer.setUint32(0, randomLo32 & 4294967295, littleEndian);
    idLastBuffer.setUint32(4, randomHi32 & 4294967295, littleEndian);
    idLastBuffer.setUint16(8, randomHi16, littleEndian);
    idLastBuffer.setUint16(10, timestamp & 0xFFFF, littleEndian);
    idLastBuffer.setUint32(12, (timestamp / 0x10000) | 0, littleEndian);
    const lo = idLastBuffer.getBigUint64(0, littleEndian);
    const hi = idLastBuffer.getBigUint64(8, littleEndian);
    return (hi << 64n) | lo;
}
//# sourceMappingURL=index.js.map