#include "command.h"
#include "uart_ring_buffer.h"
#include "led.h"
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>

/*
 协议说明（依据用户提供的旧实现）：
 Host -> Device 帧格式：
   [0] HEADER = 0xD5
   [1] BOARD_TYPE = 0x03
   [2] LEN = 数据区字节数
   [3..(3+LEN-1)] 数据
   [last] CRC = 从下标 1 到 (last-1) 的累加和低 8 位

 数据示例（两字节命令）："M1" / "M2" / "M3"

 Device -> Host 应答：复用 0xB5 开头：
   [0] 0xB5, [1] TYPE(例如 0xF0=OK, 0xF1..=错误类), [2] LEN, [3..] payload, [last] CRC（同上规则）
*/

// 旧工程中的外部状态与复位函数（本工程暂不直接使用，按要求保留为注释）：
// extern bool g_statusSwitch;     // 来自其他业务模块
// void fwdgt_reset_mcu(void);     // 看门狗复位

#define PROTOCOL_PACKAGE_HEADER   0xD5
#define PROTOCOL_BOARD_TYPE       0x03
#define PROTOCOL_PACKAGE_LENGTH   0x02

#define PACKAGE_MIN_LENGTH        6

/* 可选的应答类型定义（与示例保持一致，可按需扩展） */
#define RESP_HEADER               0xB5
#define RESP_TYPE_OK              0xF0
#define RESP_TYPE_CRC_ERR         0xF1
#define RESP_TYPE_HEADER_ERR      0xF2
#define RESP_TYPE_TYPE_ERR        0xF3
#define RESP_TYPE_LEN_ERR         0xF4

#define CMD_BUF_SIZE 64

/* 计算 CRC：从索引 1 累加到 len-2（不含 HEADER 与 CRC 字节） */
static uint8_t proto_sum_crc(const uint8_t *data, uint8_t len)
{
    uint8_t crc = 0;
    // 仅在满足协议最小帧长时计算（header + type + len + payload + crc）
    if (len < PACKAGE_MIN_LENGTH) return 0;

    // 累加从索引 1 到 len-2 的字节（不含 header 和 crc 字节）
    for (uint8_t i = 1; i < (uint8_t)(len - 1); i++) {
        crc += data[i];
    }
    return crc;
}

/* 发送应答：header(0xB5), type, len, payload[len], crc */
static void send_response(uint8_t type, const uint8_t *payload, uint8_t len)
{
    uint8_t buf_len = (uint8_t)(3 + len + 1);
    uint8_t buf[16]; // 简单场景足够，必要时可增大
    if (buf_len > sizeof(buf)) return; // 防御

    buf[0] = RESP_HEADER;
    buf[1] = type;
    buf[2] = len;
    for (uint8_t i = 0; i < len; i++) buf[3 + i] = payload ? payload[i] : 0;
    buf[buf_len - 1] = proto_sum_crc(buf, buf_len);

    for (uint8_t i = 0; i < buf_len; i++) {
        printf("%c", buf[i]);
    }
}

void handle_command(const uint8_t *cmd, uint8_t len) {
    // 期望帧：D5 03 02 'M' '1' CRC（或 'M2'/'M3'）
    if (len < PACKAGE_MIN_LENGTH) return; // 最小长度 3+2+1

    uint8_t payload_len = cmd[2];
    if (payload_len < 2) return; // 我们期望 2 字节命令

    char c0 = (char)cmd[3];
    char c1 = (char)cmd[4];
    if (c0 == 'M' && c1 == '1') {
        led_on();
    // g_statusSwitch = true; // 保留但注释：切换业务状态
        // OK: 返回 "ok"
        const uint8_t ok[] = { 'o', 'k' };
        send_response(RESP_TYPE_OK, ok, sizeof(ok));
    } else if (c0 == 'M' && c1 == '2') {
        led_off();
    // g_statusSwitch = false; // 保留但注释：切换业务状态
        const uint8_t ok[] = { 'o', 'k' };
        send_response(RESP_TYPE_OK, ok, sizeof(ok));
    } else if (c0 == 'M' && c1 == '3') {
        const uint8_t ok[] = { 'o', 'k' };
        send_response(RESP_TYPE_OK, ok, sizeof(ok));
    // fwdgt_reset_mcu(); // 保留但注释：触发 MCU 复位（依赖外部实现）
    // 或：NVIC_SystemReset();（需包含 CMSIS 头）
    } else {
        const uint8_t err[] = { 'e','r','r', 0x3C };
        send_response(RESP_TYPE_HEADER_ERR, err, sizeof(err));
    }
}

void command_process(void) {
    static uint8_t cmd_buf[CMD_BUF_SIZE];
    static uint8_t cmd_len = 0;
    static uint8_t expected_total = 0; // 0 表示尚未确定总长度

    while (uart_ring_buffer_available() > 0) {
        int byte = uart_ring_buffer_get();
        if (byte < 0) break;

        if (cmd_len == 0) {
            if ((uint8_t)byte == PROTOCOL_PACKAGE_HEADER) {
                cmd_buf[cmd_len++] = (uint8_t)byte;
                expected_total = 0; // 等待进一步字段以确定长度
            } else {
                // 丢弃非起始字节
            }
            continue;
        }

        // 累积后续字节
        cmd_buf[cmd_len++] = (uint8_t)byte;

        // 当到达长度字段（索引 2）后，确定总长度：3 + LEN + 1
        if (cmd_len == 3) {
            uint8_t payload_len = cmd_buf[2];
            expected_total = (uint8_t)(3 + payload_len + 1);
            if (expected_total > CMD_BUF_SIZE) {
                // 异常：长度超界，复位状态机
                cmd_len = 0;
                expected_total = 0;
            }
            continue;
        }

        if (expected_total > 0 && cmd_len == expected_total) {
            // 到帧尾，进行各项校验
            bool ok = true;
            if (cmd_buf[0] != PROTOCOL_PACKAGE_HEADER) {
                const uint8_t err[] = { 'e','r','r', 0x3E }; // header 错
                send_response(RESP_TYPE_HEADER_ERR, err, sizeof(err));
                ok = false;
            }
            if (ok && cmd_buf[1] != PROTOCOL_BOARD_TYPE) {
                const uint8_t err[] = { 'e','r','r', 0x3F }; // type 错
                send_response(RESP_TYPE_TYPE_ERR, err, sizeof(err));
                ok = false;
            }
            if (ok && cmd_buf[2] != PROTOCOL_PACKAGE_LENGTH) {
                const uint8_t err[] = { 'e','r','r', 0x40 }; // length 错
                send_response(RESP_TYPE_LEN_ERR, err, sizeof(err));
                ok = false;
            }
            if (ok) {
                uint8_t crc_calc = proto_sum_crc(cmd_buf, expected_total);
                uint8_t crc_recv = cmd_buf[expected_total - 1];
                if (crc_calc != crc_recv) {
                    const uint8_t err[] = { 'e','r','r', 0x3D }; // crc 错
                    send_response(RESP_TYPE_CRC_ERR, err, sizeof(err));
                    ok = false;
                }
            }

            if (ok) {
                handle_command(cmd_buf, expected_total);
            }

            // 复位，等待下一帧
            cmd_len = 0;
            expected_total = 0;
        }

        if (cmd_len >= CMD_BUF_SIZE) {
            // 防御：缓冲溢出，复位状态机
            cmd_len = 0;
            expected_total = 0;
        }
    }
}

// -----------------------------------------------------------------------------
// 下列为与传感器相关的报告函数占位，按要求“保留但注释掉”。
// 原工程中依赖 ldc1612/tmp112a 读数并通过 0xB5 帧打印上报。
// 若后续集成这些传感器驱动，可解注释并补齐实现。
//
// static uint8_t package_header[3] = {0xB5, 0xF0, 0x04};
// static uint8_t package_data[4]   = {0};
//
// void eddy_current_value_report(void) {
//     uint32_t eddy_current_value_uint32 = ldc1612_get_raw_channel_result(CHANNEL_0);
//     (void)eddy_current_value_uint32;
//     // 按原协议组帧并 printf 发送：B5 F0 04 [data3..data0] CRC
// }
//
// void tempture_value_report(void) {
//     uint32_t temperature_uint32 = tmp112a_get_raw_channel_result();
//     (void)temperature_uint32;
//     // 按原协议组帧并 printf 发送：B5 F0 04 [data3..data0] CRC
// }
