// 该文件主要实现蓝牙协议，包括特征初始化和各个特征的响应
#include <Arduino.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "ACC-BLE.h"
#include "ACC-JSON.h"
#include "ACC-BLE.h" //蓝牙相关
#include "esp_gap_bt_api.h"
#include <BLEDevice.h>
#include <stdio.h>
#include <string.h>
#include <esp_task_wdt.h> //看门狗

// 特征UUID定义
const char *SERVICE_UUID = "00FF";
const char *CHAR_COMMAND_UUID = "FF01";  // 命令（写）
const char *CHAR_INDICATE_UUID = "FF02"; // 指示（Indicate）
const char *CHAR_STATUS_UUID = "FF03";   // 状态（读）
const char *CHAR_OTA_UUID = "FF04";      // OTA（写）
const char *CHAR_NOTIFY_UUID = "FF05";   // 通知（Notify）

int BLECONFIGFLAG = 0;

// 全局BLE对象
BLEServer *pServer;
BLEService *pService;
BLECharacteristic *pCmdChar, *pIndicateChar, *pStatusChar, *pOtaChar, *pNotifyChar;
void initTask(void *pvParameters)
{
    // BLE初始化
    BLEDevice::init("KCA1124999999990006");
    BLEDevice::setMTU(517);
    pServer = BLEDevice::createServer();
    pService = pServer->createService(SERVICE_UUID);
    setupBLECharacteristics();
    pService->start();
    BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
    pAdvertising->addServiceUUID(SERVICE_UUID);
    pAdvertising->start();

    xTaskCreatePinnedToCore(
        BLETask,
        "BLE Controller",
        8192,
        NULL,
        2, // 中等优先级
        &bleTaskHandle,
        ARDUINO_RUNNING_CORE);
    vTaskDelete(NULL);
}
void BLETask(void *pvParameters)
{
    esp_task_wdt_add(NULL); // 将当前任务添加到看门狗监控
    BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();

    // 初始启动时间
    lastActiveTime = millis();

    bool isAdvertising = true;

    for (;;)
    {
        // 处理设备连接状态变化
        if (!deviceConnected && oldDeviceConnected)
        {
            delay(200);
            pServer->startAdvertising();
            oldDeviceConnected = deviceConnected;
            Serial.println("Restart broadcasting"); // 重新开始广播
        }

        if (deviceConnected && !oldDeviceConnected)
        {
            oldDeviceConnected = deviceConnected;
        }
        esp_task_wdt_reset();
        vTaskDelay(pdMS_TO_TICKS(1500)); // 需要加适当延迟，否则会占用过多资源
    }
    // FF04回调函数
    class FF04Callbacks : public BLECharacteristicCallbacks
    {
    private:
        // OTA状态跟踪变量
        bool otaInProgress = false;
        uint32_t totalBytes = 0;
        uint32_t totalPackets = 0;
        uint32_t receivedBytes = 0;
        uint32_t currentPacket = 0;
        uint8_t otaError = 0;
        uint32_t lastPacketTime = 0;

        // 校验和计算
        uint8_t calculateChecksum(const uint8_t *data, size_t length)
        {
            uint8_t sum = 0;
            for (size_t i = 0; i < length; i++)
            {
                sum += data[i];
            }
            return sum;
        }

    public:
        void onWrite(BLECharacteristic *pCharacteristic)
        {
            std::string value = pCharacteristic->getValue();
            const uint8_t *data = (uint8_t *)value.data();
            size_t length = value.length();

            // 调试输出
            // Serial.printf("\n[OTA] Received %d bytes\n", length);
            // Serial.print("HEX: ");
            // for(int i=0; i<length; i++){
            //     Serial.printf("%02X ", data[i]);
            // }
            // Serial.println();

            // 处理数据包类型
            switch (data[0])
            {
            case 0x01: // OTA开始
                handleOtaStart(data, length);
                break;

            case 0x02: // 数据包
                handleOtaData(data, length);
                break;

            case 0x03: // OTA结束
                handleOtaEnd();
                break;

            default:
                Serial.println("[OTA] Unknown command");
                break;
            }
        }

    private:
        void handleOtaStart(const uint8_t *data, size_t length)
        {
            if (length != 9 || data[0] != 0x01)
            {
                Serial.println("[OTA] Invalid start packet");
                return;
            }

            // 解析总字节数和总包数
            totalBytes = (data[1] << 24) | (data[2] << 16) | (data[3] << 8) | data[4];
            totalPackets = (data[5] << 24) | (data[6] << 16) | (data[7] << 8) | data[8];

            Serial.printf("[OTA] Start - Total:%d bytes, %d packets\n", totalBytes, totalPackets);

            if (totalBytes > 0x190000)
            { // 检查固件大小是否超过分区容量
                Serial.println("[OTA] Firmware too big");
                Update.abort();
                return;
            }

            // 初始化OTA更新
            if (Update.begin(totalBytes, U_FLASH))
            {
                otaInProgress = true;
                receivedBytes = 0;
                currentPacket = 0;
                otaError = 0;
                lastPacketTime = millis();
                Serial.println("[OTA] Update begin success");
            }
            else
            {
                Serial.println("[OTA] Update begin failed");
                // sendOtaResponse(0xFF); // 发送失败状态
            }
        }

        void handleOtaData(const uint8_t *data, size_t length)
        {
            if (!otaInProgress || length < 9)
                return;

            // 解析包头
            uint32_t packetId = (data[1] << 24) | (data[2] << 16) | (data[3] << 8) | data[4];
            uint32_t packetLen = (data[5] << 24) | (data[6] << 16) | (data[7] << 8) | data[8];
            const uint8_t *payload = &data[9];
            uint8_t receivedChecksum = data[9 + packetLen];

            // 校验数据完整性
            if (length != (9 + packetLen + 1))
            {
                Serial.println("[OTA] Invalid packet length");
                otaError = 0x01;
                return;
            }

            // 校验和验证
            uint8_t calculatedChecksum = calculateChecksum(data, 9 + packetLen);
            if (calculatedChecksum != receivedChecksum)
            {
                Serial.println("[OTA] Checksum mismatch");
                otaError = 0x02;
                return;
            }

            // 包序号检查
            if (packetId != currentPacket)
            {
                Serial.printf("[OTA] Packet loss! Expected:%d Received:%d\n", currentPacket, packetId);
                otaError = 0x03;
                return;
            }

            // 写入数据
            size_t written = Update.write(const_cast<uint8_t *>(payload), packetLen);

            if (written != packetLen)
            {
                Serial.printf("[OTA] Write failed. Expected:%d Actual:%d\n",
                              packetLen, written);
                otaError = 0x04;
                return;
            }

            // 更新状态
            receivedBytes += packetLen;
            currentPacket++;
            lastPacketTime = millis();

            // 进度显示
            if (currentPacket % 10 == 0)
            {
                float progress = (receivedBytes * 100.0) / totalBytes;
                Serial.printf("[OTA] Progress: %.1f%%\n", progress);
            }
            // Serial.println();
            //  发送确认（可选）
            //  sendOtaResponse(0x00);
        }

        void handleOtaEnd()
        {
            if (!otaInProgress)
                return;

            Serial.println("[OTA] End command received");

            if (otaError == 0 && receivedBytes == totalBytes)
            {
                if (Update.end(true))
                {
                    Serial.printf("[OTA] Update success! %d bytes\n", receivedBytes);
                    // sendOtaResponse(0x00);

                    // 延迟重启让响应有时间发送
                    delay(1000);
                    ESP.restart();
                }
                else
                {
                    Serial.println("[OTA] Update end failed");
                    // sendOtaResponse(0xFF);
                }
            }
            else
            {
                Update.abort();
                Serial.println("[OTA] Update aborted");
                // sendOtaResponse(otaError);
            }

            // 重置状态
            otaInProgress = false;
        }
    };

    // 蓝牙初始化函数，初始化不同的特征值
    void setupBLECharacteristics()
    {
        // OTA特征（写）
        pOtaChar = pService->createCharacteristic(
            CHAR_OTA_UUID,
            BLECharacteristic::PROPERTY_WRITE);
        pOtaChar->setCallbacks(new FF04Callbacks());
        pOtaChar->setAccessPermissions(ESP_GATT_PERM_WRITE);
    }
