#include "xlt_trade_demo.h"

#include <cstdio>
#include <cstring>
#include <unistd.h>

using namespace x1;

XLTTradeDemo::XLTTradeDemo() {
    api_ = XLTTradeApi::create();
}

const char* XLTTradeDemo::api_version() const {
    return api_->get_api_version();
}

uint32_t XLTTradeDemo::trading_day() const {
    return api_->get_trading_day();
}

uint64_t XLTTradeDemo::next_request_id() {
    request_id_++;
    return request_id_.load();
}

bool XLTTradeDemo::initialize() {
    // 配置
    XLTTradeConfig config;
    config.set_trading_day(20260310);                   ///< （必填）设置交易日，格式YYYYMMDD，如20230901。用户需明确指定交易日，生产环境为当前交易日，测试环境为测试柜台指定的交易日。若与柜台交易日不一致，登录将报错。
    config.set_local_addr(                              ///< （必填）设置本地网卡IP地址。生产环境中，trade对应网卡建议为solarflare网卡，solarflare网卡将自动使用ef_vi，以便达到最优的性能，非solarflare网卡则回退到内核sock模式
        "192.168.24.170",                           ///< agw 连接agw的本地网卡IP，生产环境需为AGW接入网段IP
        "192.168.20.170"                            ///< trade 连接快速报单的本地网卡IP，生产环境需为快速报单网段IP
        );
    config.add_agw_addr("192.168.5.215", 6060);    ///< （必填）添加网关地址, ip_addr agw IP地址, port agw端口。请向券商获取agw地址和端口，可重复调用添加多个agw地址，每次登录会随机选取当前可用的agw
    config.set_order_timeout(10);                       ///< （选填）设置订单超时时间，单位秒，默认10秒。委托请求时，当达到此超时时间没有收到任何响应，将触发on_order_timeout回调，提示用户在此时间内未收到任何订单响应或回报，但不代表委托失败！！用户可选择调用resend_order_request接口重发订单。
    config.set_order_seq_self_define(false);            ///< （选填）设置是否启用用户自定义订单序号，默认false。
                                                        ///< 注意！！除非您非常清楚自定义序号规则，否则请勿开启。
                                                        ///< 默认情况下，API会自动生成订单序号，用户无需关心订单序号的生成规则；
                                                        ///< 若用户启用自定义订单序号，则用户在每次下单时，必须在xlt_order_insert_info_t或xlt_cancel_order_t结构体中指定order_sequence字段
                                                        ///< 注意！！启用自定义订单序号后，用户必须确保每次下单时，order_sequence字段值唯一，否则可能导致重单，重单将没有任何响应！！！order_sequence字段取值范围[0, 2^20-1]
                                                        ///< 注意！！启用自定义订单序号后，建议委托和撤单使用不同的订单序号分段，以便管理委托和撤单，例如委托使用0~500000，撤单使用500001~1000000

    // API初始化，在使用之前调用，只需调用一次。
    if (!api_->initialize(&config, this)) {
        auto error_info = api_->get_last_error();
        printf("initialize failed: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info.error_code_type,
                    error_info.error_code,
                    error_info.error_msg);
        return false;
    }
    printf("initialize success\n");
    return true;
}

bool XLTTradeDemo::login() {
    if (session_id_ != 0) {
        api_->logout(session_id_);
    }
    session_id_ = 0;
    login_success_.store(false);
    login_finished_.store(false);

    // 登录账号信息
    const auto request_id = next_request_id();          ///< request_id，用于定位本次请求
    const uint8_t client_id = 99;                               ///< 客户端标识ID（委托源ID），用户可自定义，取值为[0, 255]。
                                                                ///< 在本次登录session中进行的委托以及回报，系统都将打上此client_id标记，用于用户进行委托隔离。
    char pub_key_base64[256] = "XXXXXXXXXXXXXX";                ///< 用户公钥(长度64字节)，暂未启用
    char account_name[CONST_ACC_NAME_LEN] = "88888888888801";   ///< 登录账号
    char password[256] = "12345678";                            ///< 登录密码

    // 登录请求
    const bool result = api_->login(request_id, client_id, account_name, password, pub_key_base64);
    if (!result) {
        auto error_info = api_->get_last_error();
        printf("login failed: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info.error_code_type,
                    error_info.error_code,
                    error_info.error_msg);
        return false;
    }

    // 等待登录响应
    while (!login_finished_.load()) {
        usleep(1000);
    }
    return login_success_.load();
}

bool XLTTradeDemo::subscribe_trade_message() {
    // 新接口：先选择订阅的交易消息类型（可按位或）
    trade_message_type_t trade_msg_type = 0;
    trade_msg_type |= TradeMessageType::REPORT | TradeMessageType::RAW_REPORT | TradeMessageType::ORDER_BOOK;

    if (!api_->subscribe_trade_message(session_id_, next_request_id(), trade_msg_type,
                                       TradeResumeType::QUICK, 0)) {
        auto error_info = api_->get_last_error();
        printf("subscribe_trade_message failed: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info.error_code_type,
                    error_info.error_code,
                    error_info.error_msg);
        return false;
    }
    printf("subscribe_trade_message request send success\n");
    return true;
}

bool XLTTradeDemo::query_assets(uint64_t account_index) {
    // 查询资金信息
    if (!api_->query_assets(session_id_, next_request_id(), account_index)) {
        auto error_info = api_->get_last_error();
        printf("query_assets failed: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info.error_code_type,
                    error_info.error_code,
                    error_info.error_msg);
        return false;
    }
    printf("query_assets request send success\n");
    return true;
}

bool XLTTradeDemo::query_positions(uint64_t account_index) {
    // 查询持仓信息
    char security_code[CONST_STR_SECURITY_CODE_LEN] = "";
    // 当security_code为空，ExchangeIndex::INIT时，表示查询所有持仓
    if (!api_->query_positions(session_id_, next_request_id(), security_code, ExchangeIndex::INIT, account_index)) {
        auto error_info = api_->get_last_error();
        printf("query_positions failed: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info.error_code_type,
                    error_info.error_code,
                    error_info.error_msg);
        return false;
    }
    printf("query_positions request send success\n");
    return true;
}

bool XLTTradeDemo::query_orders(uint64_t account_index) {
    // 查询订单（根据条件查询）
    xlt_order_query_param_t order_query_param = {};
    order_query_param.xid = 0;    ///< 需要查询的委托编号，如果为0则根据后续条件进行查询，如果不为0，则只查询指定订单，忽略后续查询条件
    std::strcpy(order_query_param.security_code, ""); ///< 证券代码，可以为空
    if (!api_->query_orders(session_id_, next_request_id(), &order_query_param, account_index)) {
        auto error_info = api_->get_last_error();
        printf("query_orders failed: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info.error_code_type,
                    error_info.error_code,
                    error_info.error_msg);
        return false;
    }
    printf("query_orders request send success\n");
    return true;
}

bool XLTTradeDemo::query_orders_by_page(uint64_t account_index) {

    const uint32_t request_count = 2;
    auto query_reference = xlt_page_query_reference_t::create();
    if (!api_->query_orders_by_page(session_id_, next_request_id(), request_count, &query_reference, account_index)) {
        auto error_info = api_->get_last_error();
        printf("query_orders_by_page failed: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info.error_code_type,
                    error_info.error_code,
                    error_info.error_msg);
        return false;
    }
    printf("query_orders_by_page request send success\n");
    return true;
}

bool XLTTradeDemo::query_trades(uint64_t account_index) {
    // 查询成交, xid若填0表示查询所有
    if (!api_->query_trades(session_id_, next_request_id(), 0, account_index)) {
        auto error_info = api_->get_last_error();
        printf("query_trades failed: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info.error_code_type,
                    error_info.error_code,
                    error_info.error_msg);
        return false;
    }
    printf("query_trades request send success\n");
    return true;
}

uint64_t XLTTradeDemo::insert_order() {
    // 订单委托
    xlt_order_insert_info_t order_info = {};
    std::strcpy(order_info.security_code, "600010"); // 证券代码
    order_info.exchange_index = ExchangeIndex::SH;  // 交易市场
    order_info.price = 111600;                       // 委托价格，放大1万倍
    order_info.quantity = 1500;                     // 委托数量
    order_info.order_type = OrderType::LIMIT_PRICE; // 报价类型，限价委托
    order_info.side = Side::BUY;                    // 买卖方向
    order_info.business_type = BusinessType::CASH;  // 业务类型，股票现货

    const uint64_t xid = api_->insert_order(session_id_, &order_info, trade_token_);   // 算法厂商、PB或者代理委托场景才需要传trade_token_参数，否则默认为0即可
    if (xid == 0) {
        auto error_info = api_->get_last_error();
        printf("insert_order failed: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info.error_code_type,
                    error_info.error_code,
                    error_info.error_msg);

    } else {
        printf("insert_order request send success: { xid = %lu }\n", xid);
    }
    return xid;
}

uint64_t XLTTradeDemo::cancel_order(uint64_t xid) {
    // 撤单
    xlt_cancel_order_info_t cancel_order = {0, xid};
    const uint64_t cancel_xid = api_->cancel_order(session_id_, &cancel_order, trade_token_); // 算法厂商、PB或者代理委托场景才需要传trade_token_参数，否则默认为0即可
    if (cancel_xid == 0) {
        auto error_info = api_->get_last_error();
        printf("cancel_order failed: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info.error_code_type,
                    error_info.error_code,
                    error_info.error_msg);
    }
    printf("cancel_order request send success: { cancel_xid = %lu }\n", cancel_xid);
    return cancel_xid;
}

bool XLTTradeDemo::submit_counter_fund_transfer_request(const FundTransSide side, amount_t amount, uint64_t trade_token) {
    char biz_no[20]={0};
    if (!api_->submit_counter_fund_transfer_request(session_id_, next_request_id(), side, amount, biz_no, trade_token)) {
        auto error_info = api_->get_last_error();
        printf("submit_counter_fund_transfer_request failed: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info.error_code_type,
                    error_info.error_code,
                    error_info.error_msg);
        return false;
    }
    printf("submit_counter_fund_transfer_request send success: { biz_no = %s }\n", biz_no);
    return true;
}

bool XLTTradeDemo::submit_cluster_fund_transfer_request(amount_t amount, uint64_t trade_token) {
    char biz_no[20]={0};
    if (!api_->submit_cluster_fund_transfer_request(session_id_, next_request_id(), amount, biz_no, trade_token)) {
        auto error_info = api_->get_last_error();
        printf("submit_cluster_fund_transfer_request failed: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info.error_code_type,
                    error_info.error_code,
                    error_info.error_msg);
        return false;
    }
    printf("submit_cluster_fund_transfer_request send success: { biz_no = %s }\n", biz_no);
    return true;
}

bool XLTTradeDemo::rebuild_trade_message(uint64_t start_sequence, uint64_t end_sequence, uint64_t account_index) {
    trade_message_type_t trade_msg_type = 0;
    trade_msg_type |= TradeMessageType::REPORT | TradeMessageType::RAW_REPORT | TradeMessageType::ORDER_BOOK;

    if (!api_->rebuild_trade_message(session_id_, next_request_id(), trade_msg_type, start_sequence, end_sequence, account_index)) {
        auto error_info = api_->get_last_error();
        printf("rebuild_trade_message failed: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info.error_code_type, error_info.error_code, error_info.error_msg);
        return false;
    }
    printf("rebuild_trade_message request send success: { start_sequence = %lu, end_sequence = %lu }\n", start_sequence, end_sequence);
    return true;
}

bool XLTTradeDemo::query_init_assets(uint64_t account_index) {
    if (!api_->query_init_assets(session_id_, next_request_id(), account_index)) {
        auto error_info = api_->get_last_error();
        printf("query_init_assets failed: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info.error_code_type, error_info.error_code, error_info.error_msg);
        return false;
    }
    printf("query_init_assets request send success\n");
    return true;
}

bool XLTTradeDemo::query_init_positions(uint64_t account_index) {
    // 查询持仓信息
    char security_code[CONST_STR_SECURITY_CODE_LEN] = "";
    if (!api_->query_init_positions(session_id_, next_request_id(), security_code, ExchangeIndex::INIT, account_index)) {
        auto error_info = api_->get_last_error();
        printf("query_init_positions failed: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info.error_code_type, error_info.error_code, error_info.error_msg);
        return false;
    }
    printf("query_init_positions request send success\n");
    return true;
}

bool XLTTradeDemo::query_trade_account_info(uint64_t account_index) {
    if (!api_->query_trade_account_info(session_id_, next_request_id(), account_index)) {
        auto error_info = api_->get_last_error();
        printf("query_trade_account_info failed: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info.error_code_type, error_info.error_code, error_info.error_msg);
        return false;
    }
    printf("query_trade_account_info request send success\n");
    return true;
}

void XLTTradeDemo::print_init_assets() {
    const xlt_init_asset_info_t* init_assets = api_->get_init_assets(session_id_);
    if (!init_assets) {
        printf("get_init_assets: null\n");
        return;
    }
    printf("get_init_assets: { account_index = %lu, initial_amount = %ld, fund_balance = %ld }\n",
                init_assets->account_index, (long)init_assets->initial_amount, (long)init_assets->fund_balance);
}

void XLTTradeDemo::print_init_positions() {
    const XLTInitPositionList* init_positions = api_->get_init_positions(session_id_);
    if (!init_positions) {
        printf("get_init_positions: null\n");
        return;
    }
    size_t data_count = init_positions->data_count();
    printf("get_init_positions: { data_count = %zu }\n", data_count);
    for (size_t i = 0; i < data_count; ++i) {
        const auto* p = init_positions->get(static_cast<int>(i));
        printf("  [%zu]: { account_index = %lu, security_code = %s, exchange_index = %d, initial_quantity = %ld, total_quantity = %ld, frozen_quantity = %ld }\n",
                    i, p->account_index, p->security_code, (int)p->exchange_index,
                    (long)p->initial_quantity, (long)p->total_quantity, (long)p->frozen_quantity);
    }
}

uint64_t XLTTradeDemo::get_account_index() {
    uint64_t account_index = api_->get_account_index(session_id_, trade_token_);
    printf("get_account_index: { account_index = %lu }\n", account_index);
    return account_index;
}

uint64_t XLTTradeDemo::auth_trade(const char* account_name, const char* password) {
    if (trade_token_ != 0) {
        api_->deauth_trade(session_id_, next_request_id(), trade_token_);
    }
    trade_token_ = 0;
    auth_success_.store(false);
    auth_finished_.store(false);

    char pub_key_base64[256] = "XXXXXXXXXXXXXX";
    if (!api_->auth_trade(session_id_, next_request_id(), account_name, password, pub_key_base64, nullptr)) {
        auto error_info = api_->get_last_error();
        printf("auth_trade failed: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info.error_code_type, error_info.error_code, error_info.error_msg);
        return false;
    }
    printf("auth_trade request send success\n");
    // 等待登录响应
    while (!auth_finished_.load()) {
        usleep(1000);
    }
    printf("auth_trade success: { trade_token: %lu }\n", trade_token_);
    return trade_token_;
}

bool XLTTradeDemo::deauth_trade(uint64_t trade_token) {
    if (!api_->deauth_trade(session_id_, next_request_id(), trade_token)) {
        auto error_info = api_->get_last_error();
        printf("deauth_trade failed: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info.error_code_type, error_info.error_code, error_info.error_msg);
        return false;
    }
    trade_token_ = 0;
    auth_success_.store(false);
    auth_finished_.store(false);
    printf("deauth_trade request send success\n");
    return true;
}

bool XLTTradeDemo::resend_order_request(uint64_t xid) {
    if (!api_->resend_order_request(session_id_, xid)) {
        auto error_info = api_->get_last_error();
        printf("resend_order_request failed: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info.error_code_type, error_info.error_code, error_info.error_msg);
        return false;
    }
    printf("resend_order_request send success: { xid = %lu }\n", xid);
    return true;
}


bool XLTTradeDemo::dump_api_performance() {
    if (!api_->dump_api_performance_info()) {
        auto error_info = api_->get_last_error();
        printf("dump_api_performance failed: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info.error_code_type, error_info.error_code, error_info.error_msg);
        return false;
    }
    printf("dump_api_performance success\n");
    return true;
}

// ---------------- XLTTradeSpi 回调实现 ----------------

void XLTTradeDemo::on_disconnect(uint64_t session_id) {
    printf("on_disconnect: { session_id = %lu }\n", session_id);
    session_id_ = 0;
    login_success_.store(false);
    login_finished_.store(false);
    // 在此重新发送登录请求
}

void XLTTradeDemo::on_login(uint64_t session_id, uint64_t request_id, const xlt_error_info_t* error_info) {
    if (error_info && error_info->error_code_type != 0) {
        printf("on_login failed: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info->error_code_type, error_info->error_code, error_info->error_msg);
        // 登录失败
        login_success_.store(false);
    }
    else {
        printf("on_login success: { session_id = %lu, request_id = %lu }\n", session_id, request_id);
        // 登录成功
        session_id_ = session_id;
        login_success_.store(true);
    }
    login_finished_.store(true);
}

void XLTTradeDemo::on_auth_trade(uint64_t session_id, uint64_t request_id, uint64_t trade_token,
    const x1::xlt_error_info_t* error_info) {
    if (error_info && error_info->error_code_type != 0) {
        printf("on_auth_trade failed: { error_code_type = %lu, error_code = %lu, error_msg = %s, session_id = %lu, request_id = %lu, trade_token = %lu }\n",
                    error_info->error_code_type, error_info->error_code, error_info->error_msg,
                    session_id, request_id, trade_token);
        auth_success_.store(false);
    } else {
        printf("on_auth_trade success: { session_id = %lu, request_id = %lu, trade_token = %lu }\n",
                    session_id, request_id, trade_token);
        // 授权认证成功
        trade_token_ = trade_token;
        auth_success_.store(true);
    }
    auth_finished_.store(true);
}

void XLTTradeDemo::on_subscribe_trade_message(uint64_t session_id, uint64_t request_id, uint64_t start_sequence,
                                              uint64_t latest_sequence, const xlt_error_info_t* error_info) {
    if (error_info && error_info->error_code_type != 0) {
        printf("on_subscribe_trade_message failed: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info->error_code_type, error_info->error_code, error_info->error_msg);
    } else {
        printf("on_subscribe_trade_message success: { session_id = %lu, request_id = %lu, start_sequence = %lu, latest_sequence = %lu }\n",
                    session_id, request_id, start_sequence, latest_sequence);
    }
}

void XLTTradeDemo::on_rebuild_trade_message(uint64_t session_id, uint64_t request_id, uint64_t start_sequence,
                                           uint64_t end_sequence, const xlt_error_info_t* error_info) {
    if (error_info && error_info->error_code_type != 0) {
        printf("on_rebuild_trade_message failed: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info->error_code_type, error_info->error_code, error_info->error_msg);
    } else {
        printf("on_rebuild_trade_message success: { session_id = %lu, request_id = %lu, start_sequence = %lu, end_sequence = %lu }\n",
                    session_id, request_id, start_sequence, end_sequence);
    }
}

void XLTTradeDemo::on_order_end(uint64_t session_id, const xlt_msg_desc_t* msg_desc, const xlt_order_end_t* order_end) {
    printf("on_order_end: { session_id = %lu, account_index = %lu, sequence = %lu, is_rebuild = %d, "
                "client_id = %d, report_id = %s, xid = %lu }\n",
                session_id,
                msg_desc->account_index, msg_desc->sequence, (int)msg_desc->is_rebuild,
                (int)order_end->client_id, order_end->report_id, order_end->xid);
}

void XLTTradeDemo::on_order_response(uint64_t session_id, const xlt_msg_desc_t* msg_desc, const xlt_order_response_t* order_response) {
    printf("on_order_response: { session_id = %lu, account_index = %lu, sequence = %lu, is_rebuild = %d, "
                "client_id = %d, report_id = %s, xid = %lu, ord_status = %c, exec_type = %c, security_code = %s, "
                "exchange_index = %d, price = %ld, quantity = %ld, side = %d, leaves_quantity = %ld, cancel_quantity = %ld, "
                "cancel_reason_id = %d, transact_time = %ld }\n",
                session_id,
                msg_desc->account_index, msg_desc->sequence, (int)msg_desc->is_rebuild,
                (int)order_response->client_id, order_response->report_id, order_response->xid,
                order_response->ord_status, order_response->exec_type, order_response->security_code,
                (int)order_response->exchange_index, order_response->price, order_response->quantity,
                (int)order_response->side, order_response->leaves_quantity, order_response->cancel_quantity,
                order_response->cancel_reason_id, order_response->transact_time);
}

void XLTTradeDemo::on_cancel_response(uint64_t session_id, const xlt_msg_desc_t* msg_desc, const xlt_cancel_response_t* cancel_response) {
    printf("on_cancel_response: { session_id = %lu, account_index = %lu, sequence = %lu, is_rebuild = %d, "
                "client_id = %d, report_id = %s, xid = %lu, origin_xid = %lu, ord_status = %c, exec_type = %c, "
                "cancel_quantity = %ld, cancel_reason_id = %d, transact_time = %ld }\n",
                session_id,
                msg_desc->account_index, msg_desc->sequence, (int)msg_desc->is_rebuild,
                (int)cancel_response->client_id, cancel_response->report_id, cancel_response->xid,
                cancel_response->origin_xid, cancel_response->ord_status, cancel_response->exec_type,
                cancel_response->cancel_quantity, cancel_response->cancel_reason_id, cancel_response->transact_time);
}

void XLTTradeDemo::on_trade_report(uint64_t session_id, const xlt_msg_desc_t* msg_desc, const xlt_trade_report_t* trade_report) {
    printf("on_trade_report: { session_id = %lu, account_index = %lu, sequence = %lu, is_rebuild = %d, "
                "client_id = %d, report_id = %s, xid = %lu, ord_status = %c, exec_type = %c, exec_id = %s, "
                "price = %ld, quantity = %ld, amount = %ld, leaves_quantity = %ld, order_quantity = %ld, transact_time = %ld }\n",
                session_id,
                msg_desc->account_index, msg_desc->sequence, (int)msg_desc->is_rebuild,
                (int)trade_report->client_id, trade_report->report_id, trade_report->xid,
                trade_report->ord_status, trade_report->exec_type, trade_report->exec_id,
                trade_report->price, trade_report->quantity, trade_report->amount, trade_report->leaves_quantity,
                trade_report->order_quantity, trade_report->transact_time);
}

void XLTTradeDemo::on_order_error_response(uint64_t session_id, const xlt_msg_desc_t* msg_desc, const xlt_order_error_response_t* error_response) {
    printf("on_order_error_response: { "
                "session_id = %lu, account_index = %lu, sequence = %lu, is_rebuild = %d, "
                "client_id = %d, report_id = %s, xid = %lu, origin_xid = %lu, transact_time = %ld, error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                session_id,
                msg_desc->account_index, msg_desc->sequence, (int)msg_desc->is_rebuild,
                (int)error_response->client_id, error_response->report_id,
                error_response->xid, error_response->origin_xid, error_response->transact_time,
                error_response->error_info.error_code_type, error_response->error_info.error_code, error_response->error_info.error_msg);
}


void XLTTradeDemo::on_raw_report(uint64_t session_id, const xlt_msg_desc_t* msg_desc, uint8_t client_id, uint64_t xid,
                                 char report_id[32],
                                 ExchangeIndex exchange_index, uint16_t platform_type, uint16_t gateway_index, uint32_t report_size, char* raw_report) {
    printf("on_raw_report: { session_id = %lu, account_index = %lu, sequence = %lu, is_rebuild = %d, client_id = %d, xid = %lu, exchange_index = %d, platform_type = %d, gateway_index = %d, report_size = %u }\n",
                session_id, msg_desc->account_index, msg_desc->sequence, msg_desc->is_rebuild, (int)client_id, xid, (int)exchange_index, platform_type, gateway_index, report_size);
}


void XLTTradeDemo::on_order_book_insert(uint64_t session_id, const x1::xlt_msg_desc_t* msg_desc,
                                          const xlt_order_book_insert_t* order_insert) {
    printf("on_order_book_insert: { session_id = %lu, account_index = %lu, sequence = %lu, is_rebuild = %d, "
                "client_id = %u, account_index = %lu, xid = %lu, origin_xid = %lu, order_status = %d, is_cancel_flag = %u, "
                "cl_order_id = %s, origin_cl_order_id = %s, "
                "security_code = %s, exchange_index = %d, order_type = %d, side = %d, business_type = %d, "
                "order_price = %ld, order_quantity = %ld, order_amount = %ld, order_fee = %ld, insert_time = %ld }\n",
                session_id, msg_desc->account_index, msg_desc->sequence, (int)msg_desc->is_rebuild,
                (unsigned)order_insert->client_id, order_insert->account_index,
                order_insert->xid, order_insert->origin_xid, (int)order_insert->order_status, (unsigned)order_insert->is_cancel_flag,
                order_insert->cl_order_id, order_insert->origin_cl_order_id,
                order_insert->security_code, (int)order_insert->exchange_index,
                (int)order_insert->order_type, (int)order_insert->side, (int)order_insert->business_type,
                order_insert->order_price, order_insert->order_quantity,
                order_insert->order_amount, order_insert->order_fee, order_insert->insert_time);
}

void XLTTradeDemo::on_order_book_update(uint64_t session_id, const x1::xlt_msg_desc_t* msg_desc,
                                               const xlt_order_book_update_t* order_update) {

    printf("on_order_book_update: { session_id = %lu, account_index = %lu, sequence = %lu, is_rebuild = %d, "
                "client_id = %u, account_index = %lu, xid = %lu, origin_xid = %lu, order_status = %d, is_cancel_flag = %u, "
                "cl_order_id = %s, origin_cl_order_id = %s, "
                "trade_quantity = %ld, trade_amount = %ld, trade_fee = %ld, trade_fix_fee = %ld, trade_count = %u, "
                "leaves_quantity = %ld, cancel_quantity = %ld, trade_time = %ld, cancel_time = %ld, update_time = %ld, "
                "report_type = %u }\n",
                session_id, msg_desc->account_index, msg_desc->sequence, (int)msg_desc->is_rebuild,
                (unsigned)order_update->client_id, order_update->account_index,
                order_update->xid, order_update->origin_xid, (int)order_update->order_status, (unsigned)order_update->is_cancel_flag,
                order_update->cl_order_id, order_update->origin_cl_order_id,
                order_update->trade_quantity, order_update->trade_amount, order_update->trade_fee,
                order_update->trade_fix_fee, order_update->trade_count,
                order_update->leaves_quantity, order_update->cancel_quantity,
                order_update->trade_time, order_update->cancel_time, order_update->update_time,
                (unsigned)order_update->report_type);

    const auto& rpt = order_update->report;
    switch (order_update->report_type) {
        case TradeReportType::ORDER_RESPONSE:
        printf("  report(order_response): { client_id = %d, report_id = %s, xid = %lu, ord_status = %c, exec_type = %c, security_code = %s, "
                        "exchange_index = %d, price = %ld, quantity = %ld, side = %d, leaves_quantity = %ld, cancel_quantity = %ld, "
                        "cancel_reason_id = %d, transact_time = %ld }\n",
                        (int)rpt.order_response.client_id, rpt.order_response.report_id, rpt.order_response.xid,
                        rpt.order_response.ord_status, rpt.order_response.exec_type, rpt.order_response.security_code,
                        (int)rpt.order_response.exchange_index, rpt.order_response.price, rpt.order_response.quantity,
                        (int)rpt.order_response.side, rpt.order_response.leaves_quantity, rpt.order_response.cancel_quantity,
                        rpt.order_response.cancel_reason_id, rpt.order_response.transact_time);
            break;
        case TradeReportType::CANCEL_RESPONSE:
        printf("  report(cancel_response): { client_id = %d, report_id = %s, xid = %lu, origin_xid = %lu, ord_status = %c, exec_type = %c, "
                        "cancel_quantity = %ld, cancel_reason_id = %d, transact_time = %ld }\n",
                        (int)rpt.cancel_response.client_id, rpt.cancel_response.report_id, rpt.cancel_response.xid,
                        rpt.cancel_response.origin_xid, rpt.cancel_response.ord_status, rpt.cancel_response.exec_type,
                        rpt.cancel_response.cancel_quantity, rpt.cancel_response.cancel_reason_id, rpt.cancel_response.transact_time);
            break;
        case TradeReportType::TRADE_REPORT:
        printf("  report(trade_report): { client_id = %d, report_id = %s, xid = %lu, ord_status = %c, exec_type = %c, exec_id = %s, "
                        "price = %ld, quantity = %ld, amount = %ld, leaves_quantity = %ld, order_quantity = %ld, transact_time = %ld }\n",
                        (int)rpt.trade_report.client_id, rpt.trade_report.report_id, rpt.trade_report.xid,
                        rpt.trade_report.ord_status, rpt.trade_report.exec_type, rpt.trade_report.exec_id,
                        rpt.trade_report.price, rpt.trade_report.quantity, rpt.trade_report.amount, rpt.trade_report.leaves_quantity,
                        rpt.trade_report.order_quantity, rpt.trade_report.transact_time);
            break;
        default:
            printf("  report: { unknown_type = %u }\n", (unsigned)order_update->report_type);
            break;
    }
}

void XLTTradeDemo::on_order_book_error(uint64_t session_id, const x1::xlt_msg_desc_t* msg_desc,
                                         const xlt_order_book_error_t* order_error) {
    printf("on_order_book_error: { "
                "session_id = %lu, account_index = %lu, sequence = %lu, is_rebuild = %d, "
                "client_id = %d, account_index = %lu, xid = %lu, origin_xid = %lu, order_status = %d, is_cancel_flag = %d, "
                "cl_order_id = %s, origin_cl_order_id = %s, update_time = %ld, "
                "client_id = %d, report_id = %s, xid = %lu, origin_xid = %lu, transact_time = %ld, error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                session_id, msg_desc->account_index, msg_desc->sequence, (int)msg_desc->is_rebuild,
                (int)order_error->client_id, order_error->account_index, order_error->xid, order_error->origin_xid, (int)order_error->order_status, (int)order_error->is_cancel_flag,
                order_error->cl_order_id, order_error->origin_cl_order_id, order_error->update_time,
                (int)order_error->order_error.client_id, order_error->order_error.report_id,
                order_error->order_error.xid, order_error->order_error.origin_xid, order_error->order_error.transact_time,
                order_error->order_error.error_info.error_code_type, order_error->order_error.error_info.error_code, order_error->order_error.error_info.error_msg);
}

void XLTTradeDemo::on_asset(uint64_t session_id, const x1::xlt_msg_desc_t* msg_desc,
    const x1::xlt_asset_info_t* asset_info) {
    if (!asset_info) {
        printf("on_asset: { session_id = %lu, account_index = %lu, sequence = %lu, is_rebuild = %d, data = null }\n",
                    session_id, msg_desc->account_index, msg_desc->sequence, (int)msg_desc->is_rebuild);
        return;
    }
    printf("on_asset: { session_id = %lu, account_index = %lu, sequence = %lu, is_rebuild = %d, "
                "available_amount = %ld, withholding_amount = %ld, fund_buy_amount = %ld, fund_buy_fee = %ld, "
                "fund_sell_amount = %ld, fund_sell_fee = %ld, withdraw_amount = %ld, deposit_amount = %ld }\n",
                session_id, msg_desc->account_index, msg_desc->sequence, (int)msg_desc->is_rebuild,
                asset_info->available_amount, asset_info->withholding_amount,
                asset_info->fund_buy_amount, asset_info->fund_buy_fee,
                asset_info->fund_sell_amount, asset_info->fund_sell_fee,
                asset_info->withdraw_amount, asset_info->deposit_amount);
}

void XLTTradeDemo::on_position(uint64_t session_id, const x1::xlt_msg_desc_t* msg_desc,
    const x1::xlt_position_info_t* position_info) {
    if (!position_info) {
        printf("on_position: { session_id = %lu, account_index = %lu, sequence = %lu, is_rebuild = %d, data = null }\n",
                    session_id, msg_desc->account_index, msg_desc->sequence, (int)msg_desc->is_rebuild);
        return;
    }
    printf("on_position: { session_id = %lu, account_index = %lu, sequence = %lu, is_rebuild = %d, "
                "security_code = %s, exchange_index = %d, total_quantity = %ld, sellable_quantity = %ld, frozen_quantity = %ld }\n",
                session_id, msg_desc->account_index, msg_desc->sequence, (int)msg_desc->is_rebuild,
                position_info->security_code, (int)position_info->exchange_index,
                position_info->total_quantity, position_info->sellable_quantity, position_info->frozen_quantity);
}


void XLTTradeDemo::on_counter_fund_transfer_result(uint64_t session_id, const xlt_msg_desc_t* msg_desc,
                                          const xlt_counter_fund_transfer_result_t* r) {
    if (!r) {
        printf("on_counter_fund_transfer_result: { session_id = %lu, data = null }\n", session_id);
        return;
    }
    printf("on_counter_fund_transfer_result: { session_id = %lu, account_index = %lu, sequence = %lu, is_rebuild = %d, "
                "biz_no = %s, source = %u, side = %u, amount = %ld, request_time = %ld, result_time = %ld, status = %u, "
                "error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                session_id, msg_desc->account_index, msg_desc->sequence, (int)msg_desc->is_rebuild,
                r->biz_no, (unsigned)r->source, (unsigned)r->side, (long)r->amount,
                (long)r->request_time, (long)r->result_time, (unsigned)r->status,
                r->error_info.error_code_type, r->error_info.error_code, r->error_info.error_msg);
}

void XLTTradeDemo::on_counter_fund_transfer_request(uint64_t session_id, const xlt_msg_desc_t* msg_desc,
                                                    const xlt_counter_fund_transfer_request_t* r) {
    if (!r) {
        printf("on_counter_fund_transfer_request: { session_id = %lu, data = null }\n", session_id);
        return;
    }
    printf("on_counter_fund_transfer_request: { session_id = %lu, account_index = %lu, sequence = %lu, is_rebuild = %d, "
                "biz_no = %s, source = %u, side = %u, amount = %ld, request_time = %ld }\n",
                session_id, msg_desc->account_index, msg_desc->sequence, (int)msg_desc->is_rebuild,
                r->biz_no, (unsigned)r->source, (unsigned)r->side, (long)r->amount, (long)r->request_time);
}

void XLTTradeDemo::on_cluster_fund_transfer_request(uint64_t session_id, const xlt_msg_desc_t* msg_desc,
                                                    const xlt_cluster_fund_transfer_request_t* r) {
    if (!r) {
        printf("on_cluster_fund_transfer_request: { session_id = %lu, data = null }\n", session_id);
        return;
    }
    printf("on_cluster_fund_transfer_request: { session_id = %lu, account_index = %lu, sequence = %lu, is_rebuild = %d, "
                "biz_no = %s, source = %u, amount = %ld, request_time = %ld }\n",
                session_id, msg_desc->account_index, msg_desc->sequence, (int)msg_desc->is_rebuild,
                r->biz_no, (unsigned)r->source, (long)r->amount, (long)r->request_time);
}

void XLTTradeDemo::on_cluster_fund_transfer_result(uint64_t session_id, const xlt_msg_desc_t* msg_desc,
                                                  const xlt_cluster_fund_transfer_result_t* r) {
    if (!r) {
        printf("on_cluster_fund_transfer_result: { session_id = %lu, data = null }\n", session_id);
        return;
    }
    printf("on_cluster_fund_transfer_result: { session_id = %lu, account_index = %lu, sequence = %lu, is_rebuild = %d, "
                "biz_no = %s, source = %u, amount = %ld, request_time = %ld, result_time = %ld, status = %u, "
                "error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                session_id, msg_desc->account_index, msg_desc->sequence, (int)msg_desc->is_rebuild,
                r->biz_no, (unsigned)r->source, (long)r->amount,
                (long)r->request_time, (long)r->result_time, (unsigned)r->status,
                r->error_info.error_code_type, r->error_info.error_code, r->error_info.error_msg);
}

void XLTTradeDemo::on_query_positions(uint64_t session_id, uint64_t request_id,
                                     const XLTPositionList* positions,
                                     bool is_last, const xlt_error_info_t* error_info) {
    size_t data_count = positions ? positions->data_count() : 0;
    printf("on_query_positions: { session_id = %lu, request_id = %lu, data_count = %zu, is_last = %d }\n",
                session_id, request_id, data_count, is_last);
    if (error_info && error_info->error_code_type != 0) {
        printf("  error: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info->error_code_type, error_info->error_code, error_info->error_msg);
        return;
    }
    for (size_t i = 0; i < data_count; ++i) {
        const auto* pos = positions->get(static_cast<int>(i));
        printf("  [%zu]: { account_index = %lu, security_code = %s, exchange_index = %d, total_quantity = %ld, sellable_quantity = %ld, frozen_quantity = %ld }\n",
                    i, pos->account_index, pos->security_code, (int)pos->exchange_index,
                    pos->total_quantity, pos->sellable_quantity, pos->frozen_quantity);
    }
}

void XLTTradeDemo::on_query_assets(uint64_t session_id, uint64_t request_id,
                                  const XLTAssetList* assets,
                                  bool is_last, const xlt_error_info_t* error_info) {
    size_t data_count = assets ? assets->data_count() : 0;
    printf("on_query_assets: { session_id = %lu, request_id = %lu, data_count = %zu, is_last = %d }\n",
                session_id, request_id, data_count, is_last);
    if (error_info && error_info->error_code_type != 0) {
        printf("  error: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info->error_code_type, error_info->error_code, error_info->error_msg);
        return;
    }
    for (size_t i = 0; i < data_count; ++i) {
        const auto* asset = assets->get(static_cast<int>(i));
        printf("  [%zu]: { account_index = %lu, available_amount = %ld, withholding_amount = %ld, fund_buy_amount = %ld, fund_buy_fee = %ld, fund_sell_amount = %ld, fund_sell_fee = %ld, withdraw_amount = %ld, deposit_amount = %ld, withdrawable_amount = %ld }\n",
                    i, asset->account_index, asset->available_amount, asset->withholding_amount,
                    asset->fund_buy_amount, asset->fund_buy_fee, asset->fund_sell_amount, asset->fund_sell_fee,
                    asset->withdraw_amount, asset->deposit_amount, asset->withdrawable_amount);
    }
}

void XLTTradeDemo::on_query_orders(uint64_t session_id, uint64_t request_id,
                                  const XLTOrderList* orders,
                                  bool is_last, const xlt_error_info_t* error_info) {
    size_t data_count = orders ? orders->data_count() : 0;
    printf("on_query_orders: { session_id = %lu, request_id = %lu, data_count = %zu, is_last = %d }\n",
                session_id, request_id, data_count, is_last);
    if (error_info && error_info->error_code_type != 0) {
        printf("  error: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info->error_code_type, error_info->error_code, error_info->error_msg);
        return;
    }

    for (size_t i = 0; i < data_count; ++i) {
        const xlt_order_info_t* order = orders->get(static_cast<int>(i));
        printf("  [%zu]: { xid = %lu, origin_xid = %lu, order_status = %d, security_code = %s, exchange_index = %d, "
                    "side = %d, business_type = %d, order_price = %ld, order_quantity = %ld, order_amount = %ld, order_fee = %ld, "
                    "trade_quantity = %ld, trade_amount = %ld, trade_fee = %ld, trade_fix_fee = %ld, trade_count = %u, "
                    "leaves_quantity = %ld, cancel_quantity = %ld, insert_time = %ld, trade_time = %ld, "
                    "error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    i, order->xid, order->origin_xid, (int)order->order_status, order->security_code, (int)order->exchange_index,
                    (int)order->side, (int)order->business_type, order->order_price, order->order_quantity,
                    order->order_amount, order->order_fee, order->trade_quantity, order->trade_amount,
                    order->trade_fee, order->trade_fix_fee, order->trade_count,
                    order->leaves_quantity, order->cancel_quantity, order->insert_time, order->trade_time,
                    order->error_info.error_code_type, order->error_info.error_code, order->error_info.error_msg);
    }
}

void XLTTradeDemo::on_query_orders_by_page(uint64_t session_id, uint64_t request_id,
                                          const XLTOrderList* order_infos,
                                          uint64_t req_count, uint64_t rsp_count,
                                          const xlt_page_query_reference_t* query_reference, bool is_last,
                                          const xlt_error_info_t* error_info) {
    size_t data_count = order_infos ? order_infos->data_count() : 0;
    printf("on_query_orders_by_page: { session_id = %lu, request_id = %lu, data_count = %zu, req_count = %lu, rsp_count = %lu, is_last = %d }\n",
                session_id, request_id, data_count, req_count, rsp_count, is_last);
    if (error_info && error_info->error_code_type != 0) {
        printf("  error: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info->error_code_type, error_info->error_code, error_info->error_msg);
        return;
    }

    for (size_t i = 0; i < data_count; ++i) {
        const xlt_order_info_t* order = order_infos->get(static_cast<int>(i));
        printf("  [%zu]: { xid = %lu, origin_xid = %lu, order_status = %d, security_code = %s, exchange_index = %d, "
                    "side = %d, business_type = %d, order_price = %ld, order_quantity = %ld, order_amount = %ld, order_fee = %ld, "
                    "trade_quantity = %ld, trade_amount = %ld, trade_fee = %ld, trade_fix_fee = %ld, trade_count = %u, "
                    "leaves_quantity = %ld, cancel_quantity = %ld, insert_time = %ld, trade_time = %ld, "
                    "error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    i, order->xid, order->origin_xid, (int)order->order_status, order->security_code, (int)order->exchange_index,
                    (int)order->side, (int)order->business_type, order->order_price, order->order_quantity,
                    order->order_amount, order->order_fee, order->trade_quantity, order->trade_amount,
                    order->trade_fee, order->trade_fix_fee, order->trade_count,
                    order->leaves_quantity, order->cancel_quantity, order->insert_time, order->trade_time,
                    order->error_info.error_code_type, order->error_info.error_code, order->error_info.error_msg);
    }

    if (is_last) {
        if (rsp_count < req_count) {
            printf("all orders got\n");
        } else {
            printf("maybe more orders, call query_orders_by_page again with query_reference\n");
            api_->query_orders_by_page(session_id, request_id, 2, query_reference);
        }
    }
}

void XLTTradeDemo::on_query_trades(uint64_t session_id, uint64_t request_id,
                                  const XLTTradeReportList* trade_reports,
                                  bool is_last, const xlt_error_info_t* error_info) {
    size_t data_count = trade_reports ? trade_reports->data_count() : 0;
    printf("on_query_trades: { session_id = %lu, request_id = %lu, data_count = %zu, is_last = %d }\n",
                session_id, request_id, data_count, is_last);
    if (error_info && error_info->error_code_type != 0) {
        printf("  error: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info->error_code_type, error_info->error_code, error_info->error_msg);
        return;
    }

    for (size_t i = 0; i < data_count; ++i) {
        const auto* trade = trade_reports->get(static_cast<int>(i));
        printf("  [%zu]: { report_id = %s, xid = %lu, ord_status = %d, price = %ld, quantity = %ld, amount = %ld, leaves_quantity = %ld }\n",
                    i, trade->report_id, trade->xid, (int)trade->ord_status,
                    trade->price, trade->quantity, trade->amount, trade->leaves_quantity);
    }
}

void XLTTradeDemo::on_query_init_assets(uint64_t session_id, uint64_t request_id,
                                        const XLTInitAssetList* init_assets, bool is_last,
                                        const xlt_error_info_t* error_info) {
    size_t data_count = init_assets ? init_assets->data_count() : 0;
    printf("on_query_init_assets: { session_id = %lu, request_id = %lu, data_count = %zu, is_last = %d }\n",
                session_id, request_id, data_count, is_last);
    if (error_info && error_info->error_code_type != 0) {
        printf("  error: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info->error_code_type, error_info->error_code, error_info->error_msg);
        return;
    }
    for (size_t i = 0; i < data_count; ++i) {
        const auto* a = init_assets->get(static_cast<int>(i));
        printf("  [%zu]: { account_index = %lu, initial_amount = %ld, fund_balance = %ld }\n",
                    i, a->account_index, (long)a->initial_amount, (long)a->fund_balance);
    }
}

void XLTTradeDemo::on_query_init_positions(uint64_t session_id, uint64_t request_id,
                                           const XLTInitPositionList* init_positions, bool is_last,
                                           const xlt_error_info_t* error_info) {
    size_t data_count = init_positions ? init_positions->data_count() : 0;
    printf("on_query_init_positions: { session_id = %lu, request_id = %lu, data_count = %zu, is_last = %d }\n",
                session_id, request_id, data_count, is_last);
    if (error_info && error_info->error_code_type != 0) {
        printf("  error: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info->error_code_type, error_info->error_code, error_info->error_msg);
        return;
    }
    for (size_t i = 0; i < data_count; ++i) {
        const auto* p = init_positions->get(static_cast<int>(i));
        printf("  [%zu]: { account_index = %lu, security_code = %s, exchange_index = %d, initial_quantity = %ld, total_quantity = %ld, frozen_quantity = %ld }\n",
                    i, p->account_index, p->security_code, (int)p->exchange_index,
                    (long)p->initial_quantity, (long)p->total_quantity, (long)p->frozen_quantity);
    }
}

void XLTTradeDemo::on_query_trade_account_info(uint64_t session_id, uint64_t request_id,
    const x1::XLTTradeAccountInfoList* trade_account_infos, bool is_last, const x1::xlt_error_info_t* error_info) {
    size_t data_count = trade_account_infos ? trade_account_infos->data_count() : 0;
    printf("on_query_trade_account_info: { session_id = %lu, request_id = %lu, data_count = %zu, is_last = %d }\n",
                session_id, request_id, data_count, is_last);
    if (error_info && error_info->error_code_type != 0) {
        printf("  error: { error_code_type = %lu, error_code = %lu, error_msg = %s }\n",
                    error_info->error_code_type, error_info->error_code, error_info->error_msg);
        return;
    }
    for (size_t i = 0; i < data_count; ++i) {
        const auto* info = trade_account_infos->get(static_cast<int>(i));
        printf("  [%zu]: { account_index = %lu, account_type = %d, account_name = %s, fund_account_index = %lu, fund_account_name = %s }\n",
                    i, info->account_index, (int)info->account_type, info->account_name, info->fund_account_index, info->fund_account_name);
    }
}

void XLTTradeDemo::on_order_timeout(uint64_t session_id, uint64_t xid) {
    printf("on_order_timeout: { session_id = %lu, xid = %lu }\n", session_id, xid);
}

