#include <time.h>
#include "SocketApiProtocol.h"

#define RECV_BUFFER_SIZE    26        //接收缓冲区大小

#define PKG_CORE_STATUS     0x00      //读取核心状态
#define PKG_CAN_STATUS      0x01      //CAN盒子状态
#define PKG_TRANS_CAN       0x02      //收发CAN包

static asio::io_context io_ctx;
static std::unique_ptr<asio::ip::udp::socket> udp_socket;
uint8_t recv_buffer[RECV_BUFFER_SIZE] = {0x00};
uint8_t send_buffer[RECV_BUFFER_SIZE] = {0x00};
char TimeBuff[32] = {0x00};
char log[64] = {0x00};
asio::ip::udp::endpoint remote_endpoint;
time_t now;
struct tm* t;

void SocketApiProtocolRun(void);
void start_receive(void);
void UdpAnalysis(uint8_t* RxData);
int UdpSendData(const char* ip, uint16_t port, const uint8_t* data, size_t len);

void CallBackCoreStatus(uint8_t* RxData,uint8_t* TxData);

void SocketApiProtocolInit(uint32_t SocketPort)
{
    udp_socket = std::make_unique<asio::ip::udp::socket>(
        io_ctx,
        asio::ip::udp::endpoint(asio::ip::udp::v4(), SocketPort)
    );

    if(udp_socket && udp_socket->is_open())
    {
        std::cout << "[UDP] Listening successfully" << std::endl;
    }
    else
    {
        std::cerr << "[UDP] Socket not open" << std::endl;
    }

    std::thread UdpReceiveTask(SocketApiProtocolRun);
    UdpReceiveTask.detach();
    start_receive(); // 注册第一次接收

    std::cout << "[UDP] Listening on port " << SocketPort << std::endl;
}

void start_receive(void)
{
    udp_socket->async_receive_from(
        asio::buffer(recv_buffer, RECV_BUFFER_SIZE),
        remote_endpoint,
        [](const asio::error_code& ec, std::size_t bytes_recvd)
        {
            if(!ec && bytes_recvd == RECV_BUFFER_SIZE && recv_buffer[0] == 0x55 && recv_buffer[RECV_BUFFER_SIZE - 1] == 0xAA)
            {
                UdpAnalysis(recv_buffer);
            }
            // 再次注册接收，保持持续监听
            start_receive();
        }
    );
}

void transTimeToData(uint8_t* TxData, struct tm* t)
{
    uint8_t data[7] = {0x00};

    data[0] = t->tm_year & 0xFF;
    data[1] = (t->tm_year >> 8) & 0xFF;
    data[2] = t->tm_mon;
    data[3] = t->tm_wday;
    data[4] = t->tm_hour;
    data[5] = t->tm_min;
    data[6] = t->tm_sec;

    memcpy(TxData,data,7);
}

void UdpAnalysis(uint8_t* RxData)
{
    int command = RxData[1];

    if (SystemCall.logEn == ENABLE)
    {
        now = time(NULL);          // 获取当前时间戳（从1970-01-01秒数）
        t = localtime(&now);  // 转成本地时间
        sprintf(TimeBuff,"%d-%d-%d.log",t->tm_year,t->tm_mon,t->tm_wday);
    }

    memset(send_buffer,0x00,RECV_BUFFER_SIZE);

    /* 添加报文头尾 */
    send_buffer[0] = 0x55;
    send_buffer[RECV_BUFFER_SIZE - 1] = 0xAA;

    switch(command)
    {
        case PKG_CORE_STATUS:
            if (SystemCall.logEn == ENABLE)
            {
                logAdd(TimeBuff,"查询Core状态");
            }
            CallBackCoreStatus(RxData, send_buffer);
            break;
        case PKG_CAN_STATUS:
            break;
        case PKG_TRANS_CAN:
            break;
    }

    //如果调试使能，则加入时间
    if (SystemCall.logEn == ENABLE)
    {
        transTimeToData(&send_buffer[2],t);
    }

    UdpSendData("127.0.0.1", 12346, send_buffer, RECV_BUFFER_SIZE);

    //调试使能就记录一下，记录使用队列保证不影响收发
    if (SystemCall.logEn == ENABLE)
    {
        sprintf(log,"发送报文:");

        for (int i = 0;i < RECV_BUFFER_SIZE;i++)
        {
            sprintf(&log[10],"0x%02X ",send_buffer[i]);
        }
       

        if (SystemCall.logEn == ENABLE)
        {
            logAdd(TimeBuff,"");
        }

        logAdd(TimeBuff,TimeBuff);
    }
}

void CallBackCoreStatus(uint8_t* RxData, uint8_t* TxData)
{
    uint8_t data[4] = {0x00};

    data[0] = SystemCall.ProductInfo;              //产品信息
    data[1] = SystemCall.CanOpenStatus[0];         //通道0打开状态
    data[2] = SystemCall.CanOpenStatus[1];         //通道1打开状态
    data[3] = SystemCall.logEn;                    //日志启用状态

    memcpy(&TxData[9],data,4);
}

int UdpSendData(const char* ip, uint16_t port, const uint8_t* data, size_t len)
{
    if(!udp_socket) return 0;

    asio::error_code ec;
    asio::ip::udp::endpoint remote(asio::ip::make_address(ip), port);

    size_t sent = udp_socket->send_to(asio::buffer(data, len), remote, 0, ec);

    if(ec)
    {
        if (SystemCall.logEn == ENABLE)
        {
            printf("[UDP] Send failed: %s\n", ec.message().c_str());  
        }

        return 0;
    }
    if (SystemCall.logEn == ENABLE)
    {
        printf("[UDP] Sent %zu bytes to %s:%u\n", sent, ip, port);
    }
    
    return 1;
}

// 让你的系统循环运行 ASIO
void SocketApiProtocolRun(void)
{
    io_ctx.run();
}