/**
* @file xlt_api_config.h
 * @author 上海前路有光数字科技
 * @date 2026-01-10
 * @brief 本文件定义XLT API配置类
 */

#pragma once

#include <sys/socket.h>
#include <cstring>
#include <vector>
#include "xlt_data_type.h"

namespace x1 {
    /**
     * @brief 行情接收配置结构体
     * 配置单位为接收线程，如配置level1行情接收线程，enable配置是否启动，cpu配置绑核，配置之后将在一个独立线程中运行。
     * @remark 若需要更细粒度的配置，如level2行情分类别接收配置，请使用quote_l2_receive_cfg_t结构体
     */
    typedef struct quote_receive_cfg_t {
        bool enabled = false;   ///< 是否启用此行情接收线程
        int cpu = -1;           ///< 绑定CPU核，-1表示不绑定
        quote_receive_cfg_t() : enabled(false), cpu(-1) {}
        quote_receive_cfg_t(bool enable, int cpu_core)
            : enabled(enable), cpu(cpu_core) {}
    } quote_receive_cfg_t;
    /**
     * @brief level2行情分类别接收配置结构体
     * 上海和深圳level2行情接收配置相同，均使用此结构体，每种行情类型均可单独配置是否接收及绑核，配置之后对应类型行情接收将在一个独立线程中运行。
     */
    typedef struct quote_l2_receive_cfg_t {
        quote_receive_cfg_t stock_snapshot; ///< 股票快照接收线程配置
        quote_receive_cfg_t stock_tick;     ///< 股票逐笔接收线程配置
        quote_receive_cfg_t index;          ///< 指数接收线程配置
        quote_receive_cfg_t bond_snapshot;  ///< 债券快照接收线程配置
        quote_receive_cfg_t bond_tick;      ///< 债券逐笔接收线程配置
        quote_l2_receive_cfg_t(): stock_snapshot(), stock_tick(), index(), bond_snapshot(), bond_tick() {}
        quote_l2_receive_cfg_t(quote_receive_cfg_t s, quote_receive_cfg_t t, quote_receive_cfg_t i,
                               quote_receive_cfg_t b_s, quote_receive_cfg_t b_t)
            : stock_snapshot(s), stock_tick(t), index(i), bond_snapshot(b_s), bond_tick(b_t) {}
    } quote_l2_receive_cfg_t;

    /**
     * @brief API配置类
     * 此类用于配置XLT API的各项参数，如日志路径、日志级别、交易日、网卡地址、网关地址、行情接收配置等。
     * 用户需要在调用XLTApi::initialize方法前，创建此类实例，并设置相应的配置参数，然后将此实例传递给XLTApi::initialize方法。
     */
    class XLTApiConfig {
    public:
        XLTApiConfig() = default;
        /**
         * @brief 设置API生成文件存放路径，如日志文件等
         * @param path 文件路径
         */
        void set_path(const char* path) { strcpy(path_, path); }
        /**
         * @brief 设置日志级别
         * @param level 日志级别
         */
        void set_log_level(ApiLogLevel level) { log_level_ = level; }
        /**
         * @brief 设置交易日，格式YYYYMMDD，如20230901
         * @param trading_day 交易日
         * @remark 用户需明确指定交易日，生产环境为当前交易日，测试环境为测试柜台指定的交易日
         */
        void set_trading_day(uint64_t trading_day) { trading_day_ = trading_day; }
        /**
         * @brief 设置本地网卡IP地址
         * @param agw 连接agw的本地网卡IP，生产环境需为AGW接入网段IP
         * @param trade 连接快速报单的本地网卡IP，生产环境需为快速报单网段IP
         * @param quote 接收行情数据的本地网卡IP，生产环境需为行情接收网段IP
         * @return 设置是否成功
         * @remark 生产环境中，trade及quote对应网卡建议为solarflare网卡，solarflare网卡将自动使用ef_vi，以便达到最优的性能，非solarflare网卡则回退到内核sock模式
         */
        bool set_local_addr(const char* agw, const char* trade, const char* quote);
        /**
         * @brief 添加网关地址
         * @param ip_addr agw IP地址
         * @param port agw端口
         * @return 设置是否成功
         * @remark 请向券商获取agw地址和端口，可重复调用添加多个agw地址，每次登录会随机选取当前可用的agw
         */
        bool add_agw_addr(const char* ip_addr, uint16_t port);
        /**
         * @brief 设置内存池大小，单位MB
         * @param trade_memory_pool_size 交易内存池大小，单位MB，默认256MB
         * @param l1_memory_pool_size level1行情内存池大小，单位MB，默认8MB
         * @param l2_memory_pool_size level2行情内存池大小，单位MB，默认32MB。上海及深圳level2独立内存池，共用此配置。
         * @remark 内存池用于缓存交易和行情数据，建议根据实际交易和行情数据量进行调整
         * @remark 预留接口，当前版本暂不支持调整
         */
        void set_memory_pool_size(uint32_t trade_memory_pool_size, uint32_t l1_memory_pool_size, uint32_t l2_memory_pool_size);
        /**
         * @brief 设置请求超时时间，单位秒，建议不小于5秒
         * @param timeout 超时时间
         * @remark 查询请求时，当达到此超时时间没有任何响应，将触发on_request_timeout，提示用户查询或委托超时
         */
        void set_request_timeout(uint16_t timeout) { request_timeout_ = timeout; }
        /**
         * @brief 设置订单超时时间，单位秒，建议不小于10秒
         * @param timeout 超时时间
         * @remark 委托请求时，当达到此超时时间没有收到任何响应，将触发on_order_timeout回调，提示用户在此时间内未收到任何订单响应或回报，但不代表委托失败！！用户可选择调用resend_order_request接口重发订单。
         */
        void set_order_timeout(uint16_t timeout) { order_timeout_ = timeout; }
        /**
         * @brief 设置用户启用自定义订单序号
         * @param self_define 是否启用自定义订单序号
         * 默认情况下，API会自动生成订单序号，用户无需关心订单序号的生成规则；若用户启用自定义订单序号，则用户在每次下单时，必须在xlt_order_insert_info_t或xlt_cancel_order_t结构体中指定order_sequence字段
         * @remark 启用自定义订单序号后，用户必须确保每次下单时，order_sequence字段值唯一，否则可能导致重单，重单将没有任何响应！！！order_sequence字段取值范围[1, 2^20-1]
         * @remark 启用自定义订单序号后，建议委托和撤单使用不同的订单序号分段，以便管理委托和撤单，例如委托使用1~500000，撤单使用500001~1000000
         */
        void set_order_seq_self_define(bool self_define) { order_seq_self_define_ = self_define; }
        /**
         * @brief 配置行情接收，单线程模式
         * @param l1 level1线程配置，enable配置是否启动level1行情，cpu配置绑核
         * @param sse_l2 上海level2线程配置，enable配置是否启动接收上海level2行情，cpu配置绑核
         * @param szse_l2 深圳level2线程配置，enable配置是否启动接收深圳level2行情，cpu配置绑核
         * @remark level1(含上海及深圳)，上海level2，深圳level2分别在独立线程运行，若level2行情需要更细粒度的配置，请使用receive_quote_in_snap_tick_thread或receive_quote_in_channel_per_thread接口
         * @remark receive_quote_in_single_thread、receive_quote_in_snap_tick_thread、receive_quote_in_channel_per_thread调用其中一个即可，若都调用以最后一次调用为准
         */
        void receive_quote_in_single_thread(quote_receive_cfg_t l1, quote_receive_cfg_t sse_l2, quote_receive_cfg_t szse_l2);
        /**
         * @brief 配置行情接收，快照和逐笔独立线程模式
         * @param l1 level1线程配置，enable配置是否启动，cpu配置绑核
         * @param sse_l2_snap 上海level2快照接收线程配置，enable配置是否启动，cpu配置绑核
         * @param sse_l2_tick 上海level2逐笔接收线程配置，enable配置是否启动，cpu配置绑核
         * @param szse_l2_snap 深圳level2快照接收线程配置，enable配置是否启动，cpu配置绑核
         * @param szse_l2_tick 深圳level2逐笔接收线程配置，enable配置是否启动，cpu配置绑核
         * @remark level1(含上海及深圳)， 上海level2快照，上海level2逐笔，深圳level2快照，深圳level2逐笔，分别在独立线程运行。若level2行情需要更细粒度的配置，请使用receive_quote_in_channel_per_thread接口
         * @remark receive_quote_in_single_thread、receive_quote_in_snap_tick_thread、receive_quote_in_channel_per_thread调用其中一个即可，若都调用以最后一次调用为准
         */
        void receive_quote_in_snap_tick_thread(quote_receive_cfg_t l1, quote_receive_cfg_t sse_l2_snap, quote_receive_cfg_t sse_l2_tick, quote_receive_cfg_t
                                               szse_l2_snap, quote_receive_cfg_t szse_l2_tick);
        /**
         * @brief 配置行情接收，按行情类型独立线程模式
         * @param l1 level1线程配置，enable配置是否启动，cpu配置绑核
         * @param sse_l2 指定的行情类型线程配置，enable配置是否启动，cpu配置绑核
         * @param szse_l2 指定的行情类型线程配置，enable配置是否启动，cpu配置绑核
         * @remark level1， 上海level2各行情类型，深圳level2各行情类型，分别在独立线程运行
         * @remark receive_quote_in_single_thread、receive_quote_in_snap_tick_thread、receive_quote_in_channel_per_thread调用其中一个即可，若都调用以最后一次调用为准
         */
        void receive_quote_in_channel_per_thread(quote_receive_cfg_t l1, quote_l2_receive_cfg_t sse_l2, quote_l2_receive_cfg_t szse_l2);

        /*================= 以下为获取配置参数接口，为内部使用 ============*/
        /**
         * @brief 获取API生成文件存放路径
         * @return 文件路径
         */
        const char *path() const { return path_; }
        /**
         * @brief 获取日志级别
         * @return 日志级别
         */
        ApiLogLevel log_level() const { return log_level_; }
        /**
         * @brief 获取交易日，格式YYYYMMDD，如20230901
         * @return 交易日
         */
        uint64_t trading_day() const { return trading_day_; }
        /**
         * @brief 获取指定本地地址
         * @param index 0-AGW，1-交易，2-行情
         * @return 本地地址
         */
        sockaddr get_local_addr(uint64_t index) const;
        /**
         * @brief 获取agw地址数量
         * @return agw地址数量
         */
        uint64_t agw_count() const { return agw_count_; };
        /**
         * @brief 获取指定agw地址
         * @param index agw地址索引
         * @return agw地址
         */
        sockaddr get_agw_addr(uint64_t index) const;
        /**
         * @brief 获取交易内存池大小，单位MB
         * @return 交易内存池大小
         */
        uint32_t trade_memory_pool_size() const { return trade_memory_pool_size_; }
        /**
         * @brief 获取level1行情内存池大小，单位MB
         * @return level1行情内存池大小
         */
        uint32_t l1_memory_pool_size() const { return l1_memory_pool_size_; }
        /**
         * @brief 获取level2行情内存池大小，单位MB
         * @return level2行情内存池大小
         */
        uint32_t l2_memory_pool_size() const { return l2_memory_pool_size_; }
        /**
         * @brief 获取请求超时时间，单位秒
         * @return 请求超时时间
         */
        uint16_t request_timeout() const { return request_timeout_; }
        /**
         * @brief 获取订单超时时间，单位秒
         * @return 订单超时时间
         */
        uint16_t order_timeout() const { return order_timeout_; }
        /**
         * @brief 获取是否用户自定义订单序号
         * @return 是否用户自定义订单序号
         */
        bool is_order_seq_self_define() const { return order_seq_self_define_; }

        /**
         * @brief 获取行情接收线程模式
         * @return 0:no quote;1:in_single_thread;2:in_snap_tick_thread;3:in_channel_per_thread
         */
        uint8_t quote_thread_mode() const {return quote_thread_mode_;}
        /**
         * @brief 获取level1行情接收配置
         * @return level1行情接收配置
         */
        quote_receive_cfg_t l1_receive_cfg() const {
            return l1_receive_cfg_;
        }
        /**
         * @brief 获取上交所level2行情接收配置
         * @return 上交所level2行情接收配置
         */
        quote_l2_receive_cfg_t sse_l2_receive_cfg() const{
            return sse_l2_receive_cfg_;
        }

        quote_l2_receive_cfg_t szse_l2_receive_cfg() const {
            return szse_l2_receive_cfg_;
        }

    private:
        char path_[256] = ".";                               ///< API生成文件存放路径，如日志文件等，默认当前目录
        ApiLogLevel log_level_ = ApiLogLevel::LOG_INFO;      ///< 日志级别
        uint64_t trading_day_ = 0;                           ///< 用户配置的交易日
        sockaddr local_addr_[3] = {};                        ///< 本地地址列表，0-AGW，1-交易，2-行情
        uint64_t agw_count_ = 0;                             ///< AGW地址数量
        sockaddr agw_addr_[32] = {};                         ///< AGW地址列表
        uint32_t trade_memory_pool_size_ = 256;              ///< 交易内存池大小，单位MB，默认256MB
        uint32_t l1_memory_pool_size_ = 8;                   ///< level1行情内存池大小，单位MB，默认8MB
        uint32_t l2_memory_pool_size_ = 32;                  ///< level2行情内存池大小，单位MB，默认256MB。上海及深圳level2独立内存池，共用此配置。
        uint16_t request_timeout_ = 10;                      ///< 请求超时时间，单位秒
        uint16_t order_timeout_ = 10;                        ///< 订单超时时间，单位秒
        bool order_seq_self_define_ = false;                 ///< 是否用户自定义订单序号
        uint8_t quote_thread_mode_ = 0;                      ///< 0:no quote;1:in_single_thread;2:in_snap_tick_thread;3:in_channel_per_thread
        quote_receive_cfg_t l1_receive_cfg_;                 ///< level1行情接收配置
        quote_l2_receive_cfg_t sse_l2_receive_cfg_;          ///< 上交所level2行情接收配置
        quote_l2_receive_cfg_t szse_l2_receive_cfg_;         ///< 深交所level2行情接收配置
    };
}
