#include "tcp_client.hpp"
#include "logger.hpp"

#include <memory>

static std::unique_ptr<TcpClient> mqtt_config_client;

static std::atomic<bool> heartbeat_running{false};
static std::atomic<bool> heartbeat_ack_received{false}; // 是否收到应答
static std::thread heartbeat_thread;

static void heartbeat_task()
{
    while (heartbeat_running.load())
    {
        if (mqtt_config_client && mqtt_config_client->is_connected())
        {
            heartbeat_ack_received = false;
            // 构造并发送心跳包
            FullPacket heartPacket = ProtocolCodec::create_heartbeat_packet(g_mqtt_config.vin);
            std::vector<uint8_t> raw = ProtocolCodec::encode_full_packet(heartPacket);
            std::string payload(reinterpret_cast<const char *>(raw.data()), raw.size());
            mqtt_config_client->send_data(payload);
            LOG_INFO("[mqtt_config] Sent heartbeat.");

            // 等待10秒期间，判断是否收到回应
            for (int i = 0; i < 10; ++i)
            {
                std::this_thread::sleep_for(std::chrono::seconds(1));
                if (!heartbeat_running.load())
                    return;
            }

            if (!heartbeat_ack_received.load())
            {
                LOG_WARN("[mqtt_config] Heartbeat ACK not received within 10 seconds.");
            }
        }
        else
        {
            LOG_WARN("[mqtt_config] Not connected, stop sending heartbeat.");
            std::this_thread::sleep_for(std::chrono::seconds(10));
        }
    }
    LOG_INFO("[mqtt_config] Heartbeat thread exited.");
}

// 接收处理逻辑
static void handle_mqtt_config_message(const std::string &data)
{
    LOG_INFO("[mqtt_config] Received data, length = " + std::to_string(data.size()) + " bytes");

    std::vector<uint8_t> bytes(data.begin(), data.end());
    auto pkt_opt = ProtocolCodec::decode_full_packet(bytes);

    if (!pkt_opt.has_value())
    {
        LOG_WARN("[mqtt_config] Invalid packet received.");
        return;
    }

    const FullPacket &pkt = pkt_opt.value();

    if (pkt.command_id == 0x07 && pkt.response_flag == 0x01 && pkt.data_length == 0) // 心跳包回复
    {
        heartbeat_ack_received = true;
        LOG_INFO("[mqtt_config] Received heartbeat ACK.");
    }
    else if (pkt.command_id == 0x81 && pkt.response_flag == 0xfe && pkt.data_length > 0) // mqtt参数配置
    {
        LOG_INFO("[mqtt_config] Received mqtt config cmd.");

        auto setting_opt = ProtocolCodec::parse_mqtt_param_setting(pkt.data_unit);
        if (!setting_opt)
        {
            LOG_ERROR("[mqtt_config] Failed to parse MQTT param setting.");
            return;
        }

        const auto &setting = *setting_opt;
        LOG_INFO("[mqtt_config] Sequence = " + std::to_string(setting.sequence));
        LOG_INFO("[mqtt_config] ParamCount = " + std::to_string(setting.param_count));

        ordered_json config_json;

        for (const auto &item : setting.items)
        {
            std::string str_val(item.value.begin(), item.value.end());
            switch (item.param_id)
            {
            case 0x87: // server_ip:port
            {
                auto pos = str_val.find(':');
                if (pos != std::string::npos)
                {
                    std::string ip = str_val.substr(0, pos);
                    int port = std::stoi(str_val.substr(pos + 1));
                    config_json["server_ip"] = ip;
                    config_json["server_port"] = port;
                }
                else
                {
                    LOG_WARN("[mqtt_config] Invalid server format (expect ip:port): " + str_val);
                }
                break;
            }
            case 0x89: // username
                config_json["username"] = str_val;
                break;

            case 0x8B: // password
                config_json["password"] = str_val;
                break;

            default:
                break;
            }
        }
        LOG_INFO("[mqtt_config] config_json : " + config_json.dump(0));
        bool ret = g_mqtt_config.update_mqtt_config(config_json);

        std::vector<uint8_t> raw_reply = ProtocolCodec::make_ack_response(pkt, ret);
        std::string str_reply(reinterpret_cast<const char *>(raw_reply.data()), raw_reply.size());
        mqtt_config_client->send_data(str_reply); // 配置回复
        if (ret)
        {
            g_mqtt_config = g_mqtt_config.load_from_file("config.json");
            mqtt_restart_required = true; // 切换新的mqtt服务器
        }
    }
    else
    {
        LOG_ERROR("[mqtt_config] Unknown command flag.");
    }
}

// 状态变化处理逻辑
static void handle_mqtt_config_status(bool connected)
{
    LOG_INFO("[mqtt_config] status: " + std::string(connected ? "connected" : "disconnected"));

    if (connected)
    {
        if (!heartbeat_running.load())
        {
            heartbeat_running = true;
            heartbeat_thread = std::thread(heartbeat_task);
            LOG_INFO("[mqtt_config] Heartbeat thread started.");
        }
    }
    else
    {
        if (heartbeat_running.load())
        {
            heartbeat_running = false;
            if (heartbeat_thread.joinable())
            {
                heartbeat_thread.join();
                LOG_INFO("[mqtt_config] Heartbeat thread stopped.");
            }
        }
    }
}

void start_mqtt_config_client(const std::string &ip, int port)
{
    mqtt_config_client = std::make_unique<TcpClient>("mqtt_config", ip, port);

    mqtt_config_client->set_receive_callback(handle_mqtt_config_message);
    mqtt_config_client->set_status_callback(handle_mqtt_config_status);

    mqtt_config_client->start();
}
