// main.cpp
#include <iostream>
#include <vector>
#include <iomanip>
#include <csignal>
#include <cstring>
#include <thread>
#include <chrono>
#include <iomanip> 
#include "mqtt_controller.hpp"
#include "serial_port.hpp"
#include "tank_data.hpp"       // 包含我们新的数据结构头文件
#include <nlohmann/json.hpp>  // 包含json库头文件


// 预设指令（不含CRC）
const std::vector<uint8_t> cmd_once      = {0x01, 0x10, 0x00, 0x3B, 0x00, 0x01, 0x02, 0x00, 0x01};
const std::vector<uint8_t> cmd_get_last  = {0x01, 0x03, 0x01, 0x00, 0x00, 0x15};
const std::vector<uint8_t> cmd_continuous = {0x01 ,0x10 ,0x00 ,0x3B ,0x00 ,0x01 ,0x02 ,0x00 ,0x04 ,0xA3 ,0x18};
const std::vector<uint8_t> cmd_stop_modbus = {0x01,0x10,0x00,0x3B,0x00,0x01,0x02,0x00,0x00,0xA2,0xDB};

// --- 配置信息 ---
#define BROKER_ADDRESS "tcp://119.45.167.177:1883"
#define CLIENT_ID      "json_publisher_client_final" // 客户端ID必须唯一
#define USERNAME       "admin"                       // 替换为你的用户名
#define PASSWORD       "admin"                       // 替换为你的密码
#define TOPIC_TO_LISTEN "tank/ditu"
#define PUBLISH_TOPIC   "tank/cap_locate001"

#define TAG_COUNT 2

std::vector<uint16_t> x_local(20);

std::vector<uint16_t> y_local(20);

std::vector<int> tag_id={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};

int i=0;

// 全局的串口对象指针，用于信号处理
std::unique_ptr<SerialPort> g_serial_port;

// 全局智能指针，用于RAII和信号处理
std::unique_ptr<MqttController> g_mqtt_controller;

// 信号处理函数，用于优雅地退出
void signalHandler(int signum) {
    std::cout << "\nInterrupt signal (" << signum << ") received." << std::endl;
    if (g_serial_port) {
        g_serial_port->send(cmd_stop_modbus);
        g_serial_port->close();
    }
    exit(signum);
}


// 这是我们为 "tank/ditu" 主题专门准备的回调函数
void on_tank_ditu_message(const std::string& topic, const std::string& payload) {
    std::cout << "\n[后台消息处理] 收到来自主题 '" << topic << "' 的新消息!" << std::endl;
    std::cout << "  消息内容: " << payload << std::endl;
    // 重新打印提示符，避免被用户的当前输入行覆盖
    //std::cout << "\n输入要作为'desc'字段发布的消息 (或 'q' 退出): " << std::flush;
}

// 打印收到的消息
void print_hex(const std::vector<uint8_t>& data) {
    for (uint8_t byte : data) {
        std::cout << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(byte) << " ";
    }
    std::cout << std::dec; // 恢复十进制输出
}

// 消息处理回调函数
void onMessageReceived(const std::vector<uint8_t>& message) {
   size_t message_len = message.size();
    if (message_len == 0) {
        return;
    }

    // 使用我们推荐的 unique_ptr 方法来创建数组
    auto data_array = std::make_unique<uint8_t[]>(message_len);
    memcpy(data_array.get(), message.data(), message_len);

    // // --- 正确地以十六进制格式打印数组内容 ---
    // std::cout << "\n<-- Received " << message_len << " bytes. Copied to array:\n    ";
      
    if(data_array[10]==0x01){
        i = static_cast<int>(data_array[8]);
        x_local[i]=(static_cast<uint8_t>(data_array[13])<< 8) | data_array[14];
        y_local[i]=(static_cast<uint8_t>(data_array[15])<< 8) | data_array[16];
        
        std::cout << std::dec << "tag:" << tag_id[i]<< std::endl;
        std::cout<<" "<<"x_local:" << x_local[i] <<",y_local:" <<y_local [i]<<std::endl;
        
    }
    
    // 恢复为十进制模式是个好习惯，以免影响后续的其他输出
    std::cout << std::dec << std::endl;

    // 你也可以在这里进行CRC校验等操作
    if (message_len > 2) {
        uint16_t received_crc = (static_cast<uint16_t>(data_array[message_len - 1]) << 8) | data_array[message_len - 2];
        uint16_t calculated_crc = SerialPort::crc16(data_array.get(), message_len - 2);
        
        std::cout << "    CRC Check on array data: " 
                  << (received_crc == calculated_crc ? "OK" : "FAILED!") << std::endl;
    }

    // 重新打印菜单提示符，让用户界面更友好
    std::cout << "\nEnter your choice: " << std::flush;

}

int main(int argc, char* argv[]) {
    // 注册信号处理，以便Ctrl+C可以正常关闭串口
    signal(SIGINT, signalHandler);

    std::string port = "/dev/ttyUSB0";
    if (argc > 1) {
        port = argv[1];
    }
    g_mqtt_controller = std::make_unique<MqttController>(BROKER_ADDRESS, CLIENT_ID);
    g_serial_port = std::make_unique<SerialPort>(port);

    if (!g_serial_port->open()) {
        return 1;
    }

       // 2. 尝试连接 (异步过程)
    if (!g_mqtt_controller->connect(USERNAME, PASSWORD)) {
        std::cerr << "MQTT 客户端启动失败，程序退出。" << std::endl;
        return 1;
    }

       // 等待连接成功
    std::cout << "等待连接建立..." << std::endl;
    while (!g_mqtt_controller->isConnected()) {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }

    // 启动监听线程，并提供回调函数
    g_serial_port->startListening(onMessageReceived);

    // 3. 连接成功后，订阅监听主题并设置回调函数
    //g_mqtt_controller->subscribe(TOPIC_TO_LISTEN, on_tank_ditu_message);

    //char choice;
    //print_menu();

    g_serial_port->send(cmd_continuous);

    while(1){

  
            for(int j=0;j<TAG_COUNT;j++){

             TankWarMapData tank_data = {
                .id = tag_id[j],
                .type = "tank",
                .resWidth = 50,
                .resHeight = 50,
                .resX = x_local[j],
                .resY = y_local[j],
                .resZ = 0,
            };

            // B. 创建一个顶层JSON对象，用于组装最终消息
            json root_json;

            // C. 将 tank_data 对象放入 "body" 字段
            //    nlohmann/json 库会自动调用我们在 tank_data.hpp 中定义的 to_json 函数
            root_json["body"] = tank_data;

            // D. 添加 "header" 字段，并内联创建一个包含 message_type 的JSON对象
            root_json["head"] = {
                {"message_type", 1}
            };

            // E. 将JSON对象序列化为紧凑的字符串，适合网络传输
            std::string json_payload = root_json.dump();


            // G. 发布最终的JSON字符串
            g_mqtt_controller->publish(PUBLISH_TOPIC, json_payload);

            }
            
            std::this_thread::sleep_for(std::chrono::milliseconds(200));

    }


    std::cout << "Exiting..." << std::endl;
    // g_serial_port的析构函数会自动被调用，关闭串口和线程
    return 0;
}