/**
 * @file mqtt_client_sdk.h
 * @brief MQTT客户端标准SDK对外接口 (默认极简+高级可配，平衡好用+够用)
 * @copyright Copyright (c) 2025 芯祥联科技
 * @contact hezuo@xxltech.cn
 * @version 3.0.0 【最终定稿版，推荐正式上线】
 * @note 1. 普通用户：无需修改任何配置，使用默认值，一行创建客户端，零门槛；
 *       2. 高级用户：按需修改配置结构体中的字段，支持所有MQTT标准+业务刚需配置；
 *       3. 所有配置项均有合理默认值，所有错误码/枚举统一管理，无冗余无兼容问题；
 *       4. 覆盖100%物联网业务场景，极简够用，高级全配；
 *       5. MQTT 5.0共享订阅：客户端侧仅需配置v50_share_group，SDK自动拼接$share/前缀；Broker侧才用于共享组管理、客户端负载均衡等核心逻辑。
 */
#ifndef MQTT_CLIENT_SDK_H
#define MQTT_CLIENT_SDK_H

#include "type.h"

// ====================== Windows DLL 导出宏 ======================
#if SELF_TEST==1
#   define MQTT_API
#else
#ifdef _WIN32
#   ifdef BUILD_MQTT_DLL
#       define MQTT_API __declspec(dllexport)
#   else
#       define MQTT_API __declspec(dllimport)
#   endif
#else
#   define MQTT_API
#endif
#endif
// ================================================================

#ifdef __cplusplus
extern "C" {
#endif

/*********************************************************************************
 * 【统一归一】所有对外枚举/错误码 - SDK.h唯一管理，无其他定义
 *********************************************************************************/
typedef enum {
    MQTT_SDK_PROTOCOL_V311 = 0,    // MQTT 3.1.1 协议版本 (默认)
    MQTT_SDK_PROTOCOL_V50  = 1     // MQTT 5.0 协议版本（支持共享订阅、消息过期等高级特性）
} MqttSdkProtocolVersion;

/**
 * @brief MQTT服务质量等级 (MQTT标准协议字段，必保留)
 */
typedef enum {
    MQTT_SDK_QOS0 = 0,  // 最多一次，最快，默认值，适合：数据上报、日志推送
    MQTT_SDK_QOS1 = 1,  // 至少一次，可靠，适合：控制指令、配置下发、告警推送
    MQTT_SDK_QOS2 = 2   // 恰好一次，最高可靠，适合：金融支付、重要指令(极少用)
} MqttSdkQos;

/**
 * @brief SDK统一错误码 (语义清晰，全覆盖场景，0成功/负数失败，用户易判断)
 */
typedef enum {
    MQTT_SDK_OK          = 0,    // 操作成功 ✅
    MQTT_SDK_ERR_PARAM   = -1,   // 参数错误(空指针/非法配置/端口超限) ❌
    MQTT_SDK_ERR_MEM     = -2,   // 内存分配失败(创建客户端/缓存不足) ❌
    MQTT_SDK_ERR_NO_CONN = -3,   // 未连接服务器(未建联就发布/订阅) ❌
    MQTT_SDK_ERR_CONN    = -4,   // 连接失败(网络错误/地址错误/认证失败/版本不兼容) ❌
    MQTT_SDK_ERR_PUB     = -5,   // 发布失败(消息过长/主题非法/QoS错误) ❌
    MQTT_SDK_ERR_SUB     = -6,   // 订阅失败(主题非法/权限不足/订阅超限) ❌
    MQTT_SDK_ERR_PKT_ID  = -7,   // ✅ 新增：Packet ID非法(超出1-128范围) ❌
	MQTT_SDK_ERR_BUSY	 = -8, 
    MQTT_SDK_ERR_CREATE  = -9,
    MQTT_SDK_ERR_TIMEOUT = -10,  // 注意：原-9改为-10，保持编号连续
    MQTT_SDK_ERR_OTHER   = -99   // 其他错误(兜底，兼容所有未枚举异常) ❌
} MqttSdkErrCode;

/*********************************************************************************
 * ✅ 新增：对外公开的MQTT连接状态枚举 (业务层直接调用，标准三态，与内核完全一致)
 * 说明：枚举值固化为0/1/2，对应MQTT3.1.1标准连接生命周期，通俗易懂无歧义
 *********************************************************************************/
typedef enum
{
    MQTT_SDK_STATE_DISCONNECTED = 0,  // 未连接 / 已断开连接
    MQTT_SDK_STATE_CONNECTING    = 1,  // 正在连接（已发送CONNECT报文，等待Broker的CONNACK应答）
    MQTT_SDK_STATE_CONNECTED     = 2   // 连接成功（已收到CONNACK，可正常发布/订阅/收发消息）
} MqttSdkConnState;

/*********************************************************************************
 * ✅ 精准命名：Broker协议交互反馈类型枚举 (核心优化，剥离Conn歧义)
 *********************************************************************************/
typedef enum {
    MQTT_SDK_BROKER_RESP_CONNACK = 0,    // Broker反馈：连接应答（CONNACK）
    MQTT_SDK_BROKER_RESP_DISCONNECT = 1, // Broker反馈：断开连接（主动/异常断开）
    MQTT_SDK_BROKER_RESP_PUBACK = 2,     // Broker反馈：QoS1发布应答（PUBACK）
    MQTT_SDK_BROKER_RESP_SUBACK = 3,     // Broker反馈：订阅应答（SUBACK）
    MQTT_SDK_BROKER_RESP_UNSUBACK = 4,   // Broker反馈：取消订阅应答（UNSUBACK）
    MQTT_SDK_BROKER_RESP_QOS2_ACK = 5    // Broker反馈：QoS2消息确认（PUBREC/PUBCOMP）
} MqttSdkBrokerRespType;

/*********************************************************************************
 * ✅ 极致极简版：Broker协议交互反馈结构体 (语义精准，客户一眼看懂)
 *********************************************************************************/
typedef struct {
    bool_xxl                  client_connected;  // 客户端连接状态（仅CONNACK/DISCONNECT场景有效）
    MqttSdkBrokerRespType     resp_type;         // Broker反馈类型（连接/订阅/发布等场景）
    MqttSdkErrCode            err_code;          // 交互错误码（0=成功，负数=失败，客户仅需判断这个）
    uint16_xxl                pkt_id;            // 报文ID（SUBACK/UNSUBACK/PUBACK/QoS2场景关联用）
} MqttSdkBrokerRespStatus;

/*********************************************************************************
 * 【统一归一】所有对外数据结构体 - 全部带默认值，极简可配，高级全量
 *********************************************************************************/
/**
 * @brief MQTT消息结构体 (收发通用，极简够用，无冗余字段)
 */
typedef struct {
    const char*     topic;          // 消息主题 (必填，如："device/data")
    const uint8_xxl*  payload;        // 消息内容 (必填，二进制/字符串均可，无格式限制)
    uint32_xxl        payload_len;    // 内容长度 (必填，字节数，必须准确)
    MqttSdkQos      qos;            // 服务质量 (可选，默认填 MQTT_SDK_QOS0 即可)
    bool_xxl            retain;         // 保留消息 (可选，默认false，MQTT标准字段)
    uint32_xxl        msg_expiry;     // ✅【最小修改】单条消息过期时间(秒)，0=使用客户端全局配置，>0=自定义过期时间
                                      // 共享订阅场景下：过期时间生效，避免离线客户端重连后接收过期消息
} MqttSdkMsg;

/**
 * @brief MQTT客户端配置结构体 【核心】
 * @note 🌟 核心设计：所有字段均有【合理默认值】，用户可3种使用方式：
 *       1. 普通用户：只赋值 client_id/broker_ip/broker_port 三个必填项，其余全部默认，极简；
 *       2. 进阶用户：按需修改 clean_start/keep_alive/username/password 等常用配置；
 *       3. 高级用户：按需修改 加密/遗嘱消息/重连策略 等所有配置，功能拉满；
 *       ✅ 无嵌套结构体，配置一目了然，修改方便，不增加用户理解成本。
 */
typedef struct {
    // -------------------------- 【必填项 3个】无默认值，必须赋值 --------------------------
    const char*     client_id;      // 客户端唯一标识 (必填，如："device_001_123456")
    const char*     broker_ip;      // 服务器IP/域名 (必填，如："192.168.1.100"、"mqtt.xxx.com")
    uint16_xxl        broker_port;    // 服务器端口 (必填，默认常用值：1883(MQTT)、8883(MQTTS))

    // -------------------------- 【基础可选配置】MQTT标准字段，常用 --------------------------
    bool_xxl            clean_start;    // 是否清理会话 (可选，默认：true ✅) MQTT标准字段
    uint32_xxl        keep_alive;     // 心跳间隔(秒) (可选，默认：30 ✅) MQTT标准字段，0=关闭心跳
    const char*     username;       // 用户名 (可选，默认：NULL ❌) 业务刚需-身份认证
    const char*     password;       // 密码 (可选，默认：NULL ❌) 业务刚需-身份认证

    // -------------------------- 【高级可选配置】业务刚需+MQTT高级特性，按需开启 --------------------------
    bool_xxl            crypto_enable;  // 是否开启消息加密 (可选，默认：false ❌) 业务刚需-数据安全
    const char*     crypto_key;     // 加密密钥(16字节) (可选，默认：NULL ❌) crypto_enable=true时生效
    const char*     crypto_iv;      // 加密向量(16字节) (可选，默认：NULL ❌) crypto_enable=true时生效
    bool_xxl            will_enable;    // 是否开启遗嘱消息 (可选，默认：false ❌) MQTT标准-设备离线告警
    MqttSdkMsg      will_msg;       // 遗嘱消息内容 (可选) will_enable=true时生效
    uint32_xxl        reconnect_intv; // 断线重连间隔(秒) (可选，默认：3 ✅) 业务刚需-断网自愈
    uint32_xxl        max_reconnect;  // 最大重连次数 (可选，默认：0 ✅) 0=无限重连，>0=指定次数

    // -------------------------- 【协议版本配置】核心开关，有默认值 --------------------------
    int             mqtt_version;   // MQTT协议版本 (可选，默认：MQTT_SDK_PROTOCOL_V311)
                                    // ✅ 赋值为 MQTT_SDK_PROTOCOL_V50 即启用5.0，否则默认3.1.1

    // ====================== ✅ MQTT5.0专属全局配置【全部有默认值，3.1.1用户无需配置】======================
    // ✅ 所有字段默认值均为：不启用/无限制/最优默认行为，3.1.1版本下SDK自动忽略这些字段
    uint32_xxl        v50_msg_expiry;    // 消息默认过期时间(秒)，默认：0 → 消息永不过期
    uint32_xxl        v50_session_expiry;// 会话过期时间(秒)，默认：0 → 断开连接后会话立即失效
    uint32_xxl        v50_max_pkt_size;  // 最大报文大小(字节)，默认：0 → 不限制报文大小
    const char*     v50_share_group;   // 默认共享订阅组名（仅MQTT 5.0生效）
                                      // ✅ 客户端侧：默认NULL → 不启用共享订阅；非NULL时，订阅主题自动拼接$share/组名/前缀，仅用于标识订阅所属共享组
                                      // ✅ Broker侧：该字段用于共享组管理、客户端负载均衡、消息分发等核心业务逻辑，是共享订阅的核心配置项
} MqttSdkClientCfg;

/*********************************************************************************
 * 【统一归一】回调函数定义 - 参数极简，含义清晰，用户易实现
 *********************************************************************************/
/**
 * @brief 订阅消息接收回调 (用户核心实现，必填)
 * @param msg 收到的MQTT消息，直接使用即可
 */
typedef void (*MqttSdkMsgCb)(const MqttSdkMsg* msg);

/**
 * @brief Broker协议交互反馈回调 (用户可选实现，推荐)
 * @param resp_status Broker协议交互反馈详情（包含反馈类型、错误码、报文ID等）
 */
typedef void (*MqttSdkBrokerRespCb)(const MqttSdkBrokerRespStatus* resp_status);

/*********************************************************************************
 * 【客户端句柄】不透明指针 - 屏蔽内部实现，用户只用传参，不用关心内部结构
 *********************************************************************************/
typedef void* MqttSdkClient;

/**
 * @brief MQTT SDK 全局初始化（整个程序调用 1 次）
 */
MQTT_API MqttSdkErrCode xxl_mqtt_sdk_global_init(void);

/*********************************************************************************
 * 【核心对外接口】仅7个！全生命周期覆盖，极简无冗余，调用流程固定
 * 调用顺序：创建 → 连接 → 发布/订阅 → 断开 → 销毁 (用户易记易用)
 *********************************************************************************/
/**
 * @brief 创建MQTT客户端实例 (第一步)
 * @param cfg 客户端配置，所有字段均有默认值，普通用户仅填3个必填项即可
 * @param msg_cb 消息接收回调，必填
 * @param broker_resp_cb Broker协议交互反馈回调，可选，传NULL则不通知
 * @return 客户端句柄：非NULL=成功，NULL=失败
 */
MQTT_API MqttSdkClient xxl_mqtt_sdk_client_create(const MqttSdkClientCfg* cfg, MqttSdkMsgCb msg_cb, MqttSdkBrokerRespCb broker_resp_cb);

/**
 * @brief 连接MQTT服务器 (第二步)
 * @param client 客户端句柄
 * @return 错误码：MQTT_SDK_OK=成功，其他=失败
 */
MQTT_API MqttSdkErrCode xxl_mqtt_sdk_client_connect(MqttSdkClient client);

/**
 * @brief 发布MQTT消息 (核心功能)
 * @param client 客户端句柄
 * @param msg 要发布的消息结构体
 * @return 错误码：MQTT_SDK_OK=成功，其他=失败
 */
MQTT_API MqttSdkErrCode xxl_mqtt_sdk_client_publish(MqttSdkClient client, const MqttSdkMsg* msg);

/**
 * @brief 订阅MQTT主题 (核心功能)
 * @param client 客户端句柄
 * @param topic 要订阅的主题
 *              - 普通订阅：直接传入原始主题（如"test"）
 *              - MQTT5.0共享订阅：传入原始主题即可，SDK自动拼接$share/共享组名/前缀
 *                                【Broker侧】订阅时会根据该主题解析出共享组名，完成共享组客户端注册
 * @param qos 订阅的消息质量等级
 * @param session_share_group 【新增】会话级共享组（可选，默认NULL）
 *                            - NULL：使用实例级默认共享组（cfg->v50_share_group）；若实例级也为NULL，则非共享订阅；
 *                            - 空字符串 ""：强制禁用共享订阅（无视实例级配置，优先级最高）；
 *                            - 非空字符串：使用该会话级共享组（优先级高于实例级）；
 * @return 错误码：MQTT_SDK_OK=成功，其他=失败
 */
MQTT_API MqttSdkErrCode xxl_mqtt_sdk_client_subscribe(MqttSdkClient client, const char* topic, MqttSdkQos qos, const char* session_share_group /* = NULL */);

/**
 * @brief 取消订阅MQTT主题
 * @param client 客户端句柄
 * @param topic 要取消的主题
 *              - 普通订阅：直接传入原始主题（如"test"）
 *              - MQTT5.0共享订阅：必须传入完整的共享订阅主题（格式：$share/共享组名/原始主题，如"$share/testg/test"）
 *                                【Broker侧】取消时会根据该主题解析出共享组名，完成共享组客户端注销
 * @param session_share_group 【新增】会话级共享组（可选，默认NULL）
 *                            - NULL：匹配实例级默认共享组的订阅记录；若实例级为NULL，则匹配非共享订阅记录；
 *                            - 空字符串 ""：强制匹配非共享订阅记录（无视实例级配置）；
 *                            - 非空字符串：匹配该会话级共享组的订阅记录；
 * @return 错误码：MQTT_SDK_OK=成功，其他=失败
 * @note MQTT5.0共享订阅取消规则：此处参数用于简化匹配逻辑，无需手动拼接$share前缀
 */
MQTT_API MqttSdkErrCode xxl_mqtt_sdk_client_unsubscribe(MqttSdkClient client, const char* topic, const char* session_share_group /* = NULL */);

/**
 * @brief 断开与MQTT服务器的连接
 * @param client 客户端句柄
 * @return 错误码：MQTT_SDK_OK=成功，其他=失败
 * @note 【Broker侧】断开连接时，会自动将该客户端从所属共享组中移除，避免消息分发异常
 */
MQTT_API MqttSdkErrCode xxl_mqtt_sdk_client_disconnect(MqttSdkClient client);

/**
 * @brief 销毁MQTT客户端实例 (最后一步，释放所有资源)
 * @param client 客户端句柄
 * @note 【Broker侧】销毁时会彻底清理该客户端在共享组中的所有注册信息，释放共享组相关资源
 */
MQTT_API void xxl_mqtt_sdk_client_destroy(MqttSdkClient client);

/*********************************************************************************
 * ✅ 新增：对外唯一核心连接状态查询接口 (业务层唯一需要的状态查询函数)
 * 只读接口、非阻塞、无副作用、线程安全，返回值为上面的公开枚举
 *********************************************************************************/
MQTT_API MqttSdkConnState xxl_mqtt_sdk_client_get_conn_state(MqttSdkClient client);

/**
 * @brief MQTT协议轮询处理函数（SDK的核心心脏）
 * @param client 客户端句柄
 * @return MqttSdkErrCode 错误码：MQTT_SDK_OK=成功，其他=失败
 * @note 【关键说明，必须写在注释里，给第三方看】
 * 1. 该函数为非阻塞函数，单次调用单次处理，执行完立即返回；
 * 2. 必须在「用户的主循环/专属线程」中**周期性调用**，建议调用频率：10~50ms/次；
 * 3. 该函数内部完成：下行报文接收解析、订阅消息回调、QoS消息重传、心跳保活、断线状态检测；
 * 4. 调用频率越高，MQTT响应越及时，最低不低于200ms/次；
 */
// ====================== ✅ 核心修正行 ======================
MQTT_API MqttSdkErrCode xxl_mqtt_sdk_client_loop(MqttSdkClient client);
// ======================================================================================
// ====================== 全局生命周期接口 ======================
// ======================================================================================

/**
 * @brief MQTT SDK 全局反初始化（程序退出前调用 1 次）
 */
MQTT_API void xxl_mqtt_sdk_global_deinit(void);

#ifdef __cplusplus
}
#endif

#endif // MQTT_CLIENT_SDK_H
