/**
 * 自然写教室智能网关管理软件 V1.0
 * 
 * protocol_converter.c - BLE到MQTT协议转换模块
 * 
 * 功能说明：
 * - BLE原始帧解析为结构化笔迹数据
 * - 笔迹数据编码为MQTT JSON/二进制负载
 * - 多种消息类型转换（笔迹/状态/控制）
 * - 数据压缩与批量打包
 * - 消息序列号管理与去重
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include <math.h>

/* ======================== 常量与类型定义 ======================== */

/* BLE帧类型标识 */
#define BLE_FRAME_STROKE      0x01   /* 笔迹坐标帧 */
#define BLE_FRAME_PAGE_TURN   0x02   /* 翻页事件帧 */
#define BLE_FRAME_PEN_STATE   0x03   /* 笔状态帧（抬笔/落笔） */
#define BLE_FRAME_BATTERY     0x04   /* 电量上报帧 */
#define BLE_FRAME_HEARTBEAT   0x05   /* 心跳帧 */
#define BLE_FRAME_OTA_ACK     0x06   /* OTA响应帧 */

/* MQTT消息类型 */
#define MQTT_MSG_STROKE       0x10   /* 笔迹数据消息 */
#define MQTT_MSG_EVENT        0x20   /* 事件通知消息 */
#define MQTT_MSG_STATUS       0x30   /* 设备状态消息 */
#define MQTT_MSG_COMMAND_ACK  0x40   /* 命令应答消息 */

/* 协议参数 */
#define MAX_BATCH_POINTS      64     /* 单批次最大坐标点数 */
#define MAX_JSON_BUFFER       4096   /* JSON缓冲区大小 */
#define MAX_BINARY_PAYLOAD    2048   /* 二进制负载最大长度 */
#define COMPRESS_THRESHOLD    128    /* 触发压缩的数据量阈值(字节) */
#define SEQUENCE_NUM_MAX      65535  /* 序列号最大值 */

/* CRC-16 CCITT多项式 */
#define CRC16_CCITT_POLY      0x1021

/* BLE原始帧头结构 (与笔固件协议一致) */
typedef struct {
    uint8_t  sync_byte;        /* 同步字节 0xAA */
    uint8_t  frame_type;       /* 帧类型 */
    uint8_t  pen_id[6];        /* 笔MAC地址 */
    uint16_t payload_len;      /* 负载长度 */
    uint16_t sequence;         /* 帧序列号 */
} __attribute__((packed)) ble_frame_header_t;

/* 7字节紧凑坐标编码结构 (与笔端一致) */
typedef struct {
    uint32_t x_coord   : 20;  /* X坐标 0-1048575 */
    uint32_t y_coord   : 20;  /* Y坐标 0-1048575 */
    uint16_t pressure  : 12;  /* 压力值 0-4095 */
    uint8_t  flags     : 4;   /* 标志位 */
} stroke_point_compact_t;

/* 解码后的笔迹坐标点 */
typedef struct {
    float    x;               /* X坐标（毫米） */
    float    y;               /* Y坐标（毫米） */
    float    pressure;        /* 压力值（归一化 0.0-1.0） */
    uint32_t timestamp_ms;    /* 时间戳（毫秒） */
    uint8_t  pen_down;        /* 落笔标志 */
} decoded_point_t;

/* MQTT负载结构 */
typedef struct {
    char     topic[128];      /* MQTT主题 */
    uint8_t  payload[MAX_BINARY_PAYLOAD]; /* 负载数据 */
    uint32_t payload_len;     /* 负载长度 */
    uint8_t  qos;             /* QoS等级 */
    bool     retain;          /* 保留标志 */
    uint16_t msg_seq;         /* 消息序列号 */
} mqtt_message_t;

/* 协议转换器上下文 */
typedef struct {
    char     gateway_id[32];           /* 网关标识 */
    uint16_t next_sequence;            /* 下一个消息序列号 */
    uint16_t last_ble_seq[64];         /* 各笔最后BLE序列号(去重) */
    uint32_t total_converted;          /* 总转换消息数 */
    uint32_t total_dropped;            /* 丢弃的重复消息数 */
    uint32_t error_count;              /* 错误计数 */
    bool     use_binary_format;        /* 是否使用二进制格式 */
    bool     compression_enabled;      /* 是否启用压缩 */
} protocol_converter_ctx_t;

/* 全局协议转换器实例 */
static protocol_converter_ctx_t g_converter;

/* ======================== CRC校验 ======================== */

/**
 * 计算CRC-16 CCITT校验值
 * 用于验证BLE帧数据完整性
 */
static uint16_t crc16_ccitt(const uint8_t *data, uint32_t length)
{
    uint16_t crc = 0xFFFF;
    
    for (uint32_t i = 0; i < length; i++) {
        crc ^= (uint16_t)data[i] << 8;
        for (int j = 0; j < 8; j++) {
            if (crc & 0x8000) {
                crc = (crc << 1) ^ CRC16_CCITT_POLY;
            } else {
                crc <<= 1;
            }
        }
    }
    
    return crc;
}

/* ======================== BLE帧解析 ======================== */

/**
 * 验证BLE帧头有效性
 * 检查同步字节、帧类型范围、负载长度合理性
 */
static bool validate_ble_frame(const uint8_t *raw_data, uint32_t raw_len)
{
    if (raw_len < sizeof(ble_frame_header_t) + 2) {
        /* 数据长度不足（帧头 + CRC-16） */
        return false;
    }
    
    const ble_frame_header_t *header = (const ble_frame_header_t *)raw_data;
    
    /* 检查同步字节 */
    if (header->sync_byte != 0xAA) {
        return false;
    }
    
    /* 检查帧类型范围 */
    if (header->frame_type < BLE_FRAME_STROKE || 
        header->frame_type > BLE_FRAME_OTA_ACK) {
        return false;
    }
    
    /* 检查负载长度合理性 */
    uint32_t expected_len = sizeof(ble_frame_header_t) + header->payload_len + 2;
    if (expected_len > raw_len || header->payload_len > MAX_BINARY_PAYLOAD) {
        return false;
    }
    
    /* CRC校验 - 计算帧头+负载的CRC并与尾部CRC比较 */
    uint32_t data_len = sizeof(ble_frame_header_t) + header->payload_len;
    uint16_t calc_crc = crc16_ccitt(raw_data, data_len);
    uint16_t recv_crc = *(uint16_t *)(raw_data + data_len);
    
    if (calc_crc != recv_crc) {
        g_converter.error_count++;
        return false;
    }
    
    return true;
}

/**
 * 解码7字节紧凑坐标为浮点坐标
 * 坐标单位从点阵码单位转换为毫米
 * 压力值归一化到0.0-1.0范围
 */
static void decode_compact_point(const uint8_t *compact_data, 
                                  decoded_point_t *point)
{
    /* 从7字节紧凑编码中提取各字段 */
    uint32_t raw_x = ((uint32_t)compact_data[0] << 12) |
                     ((uint32_t)compact_data[1] << 4) |
                     ((compact_data[2] >> 4) & 0x0F);
    
    uint32_t raw_y = ((uint32_t)(compact_data[2] & 0x0F) << 16) |
                     ((uint32_t)compact_data[3] << 8) |
                     compact_data[4];
    
    uint16_t raw_pressure = ((uint16_t)compact_data[5] << 4) |
                            ((compact_data[6] >> 4) & 0x0F);
    
    uint8_t flags = compact_data[6] & 0x0F;
    
    /* 坐标转换：点阵码坐标 → 毫米（分辨率约0.3mm/单位） */
    point->x = (float)raw_x * 0.3f;
    point->y = (float)raw_y * 0.3f;
    
    /* 压力值归一化到 0.0-1.0 */
    point->pressure = (float)raw_pressure / 4095.0f;
    
    /* 落笔标志在flags低位 */
    point->pen_down = (flags & 0x01) ? 1 : 0;
}

/**
 * 解析BLE笔迹帧为坐标点数组
 * 返回实际解码的坐标点数量
 */
static int parse_stroke_frame(const uint8_t *payload, uint16_t payload_len,
                               decoded_point_t *points, int max_points)
{
    /* 每个坐标点占7字节紧凑编码 + 4字节时间戳 = 11字节 */
    int point_size = 11;
    int num_points = payload_len / point_size;
    
    if (num_points > max_points) {
        num_points = max_points;
    }
    
    for (int i = 0; i < num_points; i++) {
        const uint8_t *point_data = payload + (i * point_size);
        
        /* 解码紧凑坐标 */
        decode_compact_point(point_data, &points[i]);
        
        /* 提取时间戳 (小端序，4字节毫秒时间戳) */
        points[i].timestamp_ms = (uint32_t)point_data[7] |
                                 ((uint32_t)point_data[8] << 8) |
                                 ((uint32_t)point_data[9] << 16) |
                                 ((uint32_t)point_data[10] << 24);
    }
    
    return num_points;
}

/* ======================== 序列号去重 ======================== */

/**
 * 检查BLE帧序列号是否重复
 * 使用滑动窗口检测重复帧，防止BLE重传导致数据重复
 */
static bool is_duplicate_frame(uint8_t pen_index, uint16_t ble_sequence)
{
    if (pen_index >= 64) {
        return false;
    }
    
    uint16_t last_seq = g_converter.last_ble_seq[pen_index];
    
    /* 考虑序列号回绕：如果新序列号在旧序列号的合理范围内则认为重复 */
    if (ble_sequence == last_seq) {
        g_converter.total_dropped++;
        return true;
    }
    
    /* 更新最后序列号 */
    g_converter.last_ble_seq[pen_index] = ble_sequence;
    return false;
}

/**
 * 分配下一个MQTT消息序列号
 * 单调递增，到达最大值后回绕
 */
static uint16_t allocate_msg_sequence(void)
{
    uint16_t seq = g_converter.next_sequence;
    g_converter.next_sequence = (seq + 1) % (SEQUENCE_NUM_MAX + 1);
    return seq;
}

/* ======================== JSON编码 ======================== */

/**
 * 将笔迹坐标数组编码为JSON格式
 * 格式: {"pen_id":"xx:xx:xx","seq":N,"points":[{"x":1.2,"y":3.4,"p":0.5,"t":123},...]}
 */
static int encode_stroke_json(const char *pen_id_str,
                               const decoded_point_t *points, int num_points,
                               char *json_buf, int buf_size)
{
    int offset = 0;
    
    /* JSON头部 */
    offset += snprintf(json_buf + offset, buf_size - offset,
        "{\"gw\":\"%s\",\"pen\":\"%s\",\"seq\":%u,\"ts\":%lu,\"pts\":[",
        g_converter.gateway_id, pen_id_str,
        allocate_msg_sequence(), (unsigned long)time(NULL));
    
    /* 编码每个坐标点 */
    for (int i = 0; i < num_points && offset < buf_size - 64; i++) {
        if (i > 0) {
            json_buf[offset++] = ',';
        }
        
        offset += snprintf(json_buf + offset, buf_size - offset,
            "{\"x\":%.2f,\"y\":%.2f,\"p\":%.3f,\"t\":%u,\"d\":%d}",
            points[i].x, points[i].y, points[i].pressure,
            points[i].timestamp_ms, points[i].pen_down);
    }
    
    /* JSON尾部 */
    offset += snprintf(json_buf + offset, buf_size - offset, "]}");
    
    return offset;
}

/**
 * 将设备状态编码为JSON格式
 * 格式: {"gateway_id":"xx","pen_id":"xx","event":"battery","value":85}
 */
static int encode_status_json(const char *pen_id_str, 
                               const char *event_type,
                               int value, char *json_buf, int buf_size)
{
    return snprintf(json_buf, buf_size,
        "{\"gw\":\"%s\",\"pen\":\"%s\",\"event\":\"%s\","
        "\"value\":%d,\"ts\":%lu}",
        g_converter.gateway_id, pen_id_str, event_type,
        value, (unsigned long)time(NULL));
}

/* ======================== 简单LZ压缩 ======================== */

/**
 * 简易RLE压缩 - 对二进制负载进行行程编码压缩
 * 当连续相同字节超过3个时进行压缩
 * 返回压缩后长度，若压缩无效则返回原始长度
 */
static uint32_t rle_compress(const uint8_t *input, uint32_t input_len,
                              uint8_t *output, uint32_t output_max)
{
    if (input_len < COMPRESS_THRESHOLD) {
        /* 数据量太小，不压缩 */
        memcpy(output, input, input_len);
        return input_len;
    }
    
    uint32_t out_pos = 0;
    uint32_t i = 0;
    
    /* 写入压缩标记头 */
    output[out_pos++] = 0x52; /* 'R' - RLE标记 */
    output[out_pos++] = 0x4C; /* 'L' */
    output[out_pos++] = (input_len >> 8) & 0xFF; /* 原始长度高字节 */
    output[out_pos++] = input_len & 0xFF;         /* 原始长度低字节 */
    
    while (i < input_len && out_pos < output_max - 3) {
        uint8_t current = input[i];
        uint32_t run_len = 1;
        
        /* 统计连续相同字节 */
        while (i + run_len < input_len && 
               input[i + run_len] == current && 
               run_len < 255) {
            run_len++;
        }
        
        if (run_len >= 4) {
            /* RLE编码: 转义字节 + 重复次数 + 值 */
            output[out_pos++] = 0xFF;  /* 转义标记 */
            output[out_pos++] = (uint8_t)run_len;
            output[out_pos++] = current;
        } else {
            /* 直接拷贝非重复数据 */
            for (uint32_t j = 0; j < run_len && out_pos < output_max; j++) {
                if (current == 0xFF) {
                    /* 原始数据恰好是0xFF，需要转义 */
                    output[out_pos++] = 0xFF;
                    output[out_pos++] = 0x01;
                    output[out_pos++] = 0xFF;
                } else {
                    output[out_pos++] = current;
                }
            }
        }
        
        i += run_len;
    }
    
    /* 如果压缩后更大，返回原始数据 */
    if (out_pos >= input_len) {
        memcpy(output, input, input_len);
        return input_len;
    }
    
    return out_pos;
}

/* ======================== 核心转换接口 ======================== */

/**
 * 初始化协议转换器
 * 设置网关标识，清空序列号追踪
 */
int protocol_converter_init(const char *gateway_id, bool use_binary, 
                             bool enable_compression)
{
    memset(&g_converter, 0, sizeof(g_converter));
    strncpy(g_converter.gateway_id, gateway_id, 
            sizeof(g_converter.gateway_id) - 1);
    g_converter.use_binary_format = use_binary;
    g_converter.compression_enabled = enable_compression;
    g_converter.next_sequence = 1;
    
    /* 初始化序列号追踪数组 */
    memset(g_converter.last_ble_seq, 0xFF, sizeof(g_converter.last_ble_seq));
    
    printf("[协议转换] 初始化完成, 网关=%s, 二进制=%d, 压缩=%d\n",
           gateway_id, use_binary, enable_compression);
    return 0;
}

/**
 * 将MAC地址字节数组转换为字符串表示
 */
static void mac_to_string(const uint8_t mac[6], char *str, int str_len)
{
    snprintf(str, str_len, "%02X:%02X:%02X:%02X:%02X:%02X",
             mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}

/**
 * 核心协议转换函数
 * 将BLE原始帧转换为MQTT消息
 * 
 * @param raw_ble_data   BLE接收到的原始字节流
 * @param raw_len        原始数据长度
 * @param pen_index      笔在连接表中的索引(0-63)
 * @param mqtt_msg       输出: 转换后的MQTT消息
 * @return 0=成功, -1=帧无效, -2=重复帧, -3=转换失败
 */
int convert_ble_to_mqtt(const uint8_t *raw_ble_data, uint32_t raw_len,
                         uint8_t pen_index, mqtt_message_t *mqtt_msg)
{
    /* 步骤1: 验证BLE帧 */
    if (!validate_ble_frame(raw_ble_data, raw_len)) {
        g_converter.error_count++;
        return -1;
    }
    
    const ble_frame_header_t *header = (const ble_frame_header_t *)raw_ble_data;
    const uint8_t *payload = raw_ble_data + sizeof(ble_frame_header_t);
    
    /* 步骤2: 序列号去重 */
    if (is_duplicate_frame(pen_index, header->sequence)) {
        return -2;
    }
    
    /* 获取笔MAC地址字符串 */
    char pen_id_str[20];
    mac_to_string(header->pen_id, pen_id_str, sizeof(pen_id_str));
    
    /* 步骤3: 根据帧类型进行协议转换 */
    char json_buf[MAX_JSON_BUFFER];
    int json_len = 0;
    
    switch (header->frame_type) {
    case BLE_FRAME_STROKE: {
        /* 笔迹坐标帧 → MQTT笔迹数据消息 */
        decoded_point_t points[MAX_BATCH_POINTS];
        int num_points = parse_stroke_frame(payload, header->payload_len,
                                            points, MAX_BATCH_POINTS);
        
        if (num_points <= 0) {
            return -3;
        }
        
        /* 构建MQTT Topic: pen/{gateway_id}/stroke */
        snprintf(mqtt_msg->topic, sizeof(mqtt_msg->topic),
                 "pen/%s/stroke", g_converter.gateway_id);
        
        /* 编码为JSON负载 */
        json_len = encode_stroke_json(pen_id_str, points, num_points,
                                       json_buf, sizeof(json_buf));
        
        /* 笔迹数据使用QoS 1确保送达 */
        mqtt_msg->qos = 1;
        mqtt_msg->retain = false;
        break;
    }
    
    case BLE_FRAME_PAGE_TURN: {
        /* 翻页事件 → MQTT事件消息 */
        uint16_t page_id = payload[0] | ((uint16_t)payload[1] << 8);
        
        snprintf(mqtt_msg->topic, sizeof(mqtt_msg->topic),
                 "pen/%s/event", g_converter.gateway_id);
        
        json_len = snprintf(json_buf, sizeof(json_buf),
            "{\"gw\":\"%s\",\"pen\":\"%s\",\"event\":\"page_turn\","
            "\"page_id\":%u,\"ts\":%lu}",
            g_converter.gateway_id, pen_id_str, page_id,
            (unsigned long)time(NULL));
        
        mqtt_msg->qos = 1;
        mqtt_msg->retain = false;
        break;
    }
    
    case BLE_FRAME_PEN_STATE: {
        /* 笔状态帧 → MQTT事件消息 */
        const char *state = (payload[0] == 0x01) ? "pen_down" : "pen_up";
        
        snprintf(mqtt_msg->topic, sizeof(mqtt_msg->topic),
                 "pen/%s/event", g_converter.gateway_id);
        
        json_len = encode_status_json(pen_id_str, state, 
                                       payload[0], json_buf, sizeof(json_buf));
        
        mqtt_msg->qos = 0;
        mqtt_msg->retain = false;
        break;
    }
    
    case BLE_FRAME_BATTERY: {
        /* 电量上报帧 → MQTT状态消息 */
        uint8_t battery_pct = payload[0];
        
        snprintf(mqtt_msg->topic, sizeof(mqtt_msg->topic),
                 "gateway/%s/status", g_converter.gateway_id);
        
        json_len = encode_status_json(pen_id_str, "battery",
                                       battery_pct, json_buf, sizeof(json_buf));
        
        /* 电量信息使用QoS 0，允许丢失 */
        mqtt_msg->qos = 0;
        mqtt_msg->retain = true;  /* 保留最新电量 */
        break;
    }
    
    case BLE_FRAME_HEARTBEAT: {
        /* 心跳帧 → 更新设备在线状态，不转发至MQTT */
        /* 心跳由设备管理器处理，此处仅记录 */
        return 0;
    }
    
    default:
        return -3;
    }
    
    /* 步骤4: 将JSON数据填入MQTT消息负载 */
    if (json_len > 0 && json_len < (int)sizeof(mqtt_msg->payload)) {
        if (g_converter.compression_enabled && 
            json_len > COMPRESS_THRESHOLD) {
            /* 压缩JSON负载 */
            mqtt_msg->payload_len = rle_compress(
                (const uint8_t *)json_buf, json_len,
                mqtt_msg->payload, sizeof(mqtt_msg->payload));
        } else {
            memcpy(mqtt_msg->payload, json_buf, json_len);
            mqtt_msg->payload_len = json_len;
        }
    }
    
    mqtt_msg->msg_seq = allocate_msg_sequence();
    g_converter.total_converted++;
    
    return 0;
}

/**
 * 将云端MQTT命令消息转换为BLE控制帧
 * 支持命令类型：OTA触发、配置更新、校准指令
 * 
 * @param mqtt_payload   MQTT消息负载(JSON)
 * @param payload_len    负载长度
 * @param ble_cmd_buf    输出: BLE命令帧缓冲
 * @param buf_size       缓冲区大小
 * @return 生成的BLE命令帧长度, -1=失败
 */
int convert_mqtt_to_ble_command(const uint8_t *mqtt_payload, 
                                 uint32_t payload_len,
                                 uint8_t *ble_cmd_buf, uint32_t buf_size)
{
    /* 简易JSON解析 - 查找command字段 */
    const char *json_str = (const char *)mqtt_payload;
    const char *cmd_start = strstr(json_str, "\"command\":\"");
    
    if (cmd_start == NULL) {
        return -1;
    }
    
    cmd_start += strlen("\"command\":\"");
    
    /* 构建BLE命令帧头 */
    ble_frame_header_t *cmd_header = (ble_frame_header_t *)ble_cmd_buf;
    cmd_header->sync_byte = 0xAA;
    cmd_header->sequence = allocate_msg_sequence();
    
    uint8_t *cmd_payload = ble_cmd_buf + sizeof(ble_frame_header_t);
    uint16_t cmd_payload_len = 0;
    
    if (strncmp(cmd_start, "ota_start", 9) == 0) {
        /* OTA升级启动命令 */
        cmd_header->frame_type = BLE_FRAME_OTA_ACK;
        cmd_payload[0] = 0x01; /* OTA开始标记 */
        cmd_payload_len = 1;
    } else if (strncmp(cmd_start, "calibrate", 9) == 0) {
        /* 校准命令 */
        cmd_header->frame_type = BLE_FRAME_PEN_STATE;
        cmd_payload[0] = 0x10; /* 校准指令码 */
        cmd_payload_len = 1;
    } else {
        return -1;
    }
    
    cmd_header->payload_len = cmd_payload_len;
    
    /* 追加CRC校验 */
    uint32_t frame_len = sizeof(ble_frame_header_t) + cmd_payload_len;
    uint16_t crc = crc16_ccitt(ble_cmd_buf, frame_len);
    memcpy(ble_cmd_buf + frame_len, &crc, 2);
    
    return frame_len + 2;
}

/**
 * 获取协议转换器统计信息
 */
void protocol_converter_get_stats(uint32_t *converted, 
                                    uint32_t *dropped,
                                    uint32_t *errors)
{
    if (converted) *converted = g_converter.total_converted;
    if (dropped)   *dropped = g_converter.total_dropped;
    if (errors)    *errors = g_converter.error_count;
}

/**
 * 重置协议转换器统计计数
 */
void protocol_converter_reset_stats(void)
{
    g_converter.total_converted = 0;
    g_converter.total_dropped = 0;
    g_converter.error_count = 0;
    printf("[协议转换] 统计计数已重置\n");
}
