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

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

#define PKG_CORE_STATUS     0x00      //读取核心状态
#define PKG_CAN_STATUS      0x01      //CAN盒子状态
#define PKG_TRANS_CAN       0x02      //收发CAN包
#define PKG_CTRL_GET        0xFF      //取得控制权限

#define LOG_LEN             512       //日志长度

static asio::io_context io_ctx;       //udp上下文
static std::unique_ptr<asio::ip::udp::socket> udp_socket;       //socket
asio::ip::udp::endpoint remote_endpoint;            //socket remote
std::string RemoteIpStr;     //socket remote ip str
uint8_t recv_buffer[RECV_BUFFER_SIZE] = {0x00};     //接收缓冲区
uint8_t send_buffer[RECV_BUFFER_SIZE] = {0x00};     //发送缓冲区
char TimeBuff[64] = {0x00};                         //时间缓冲区
char StatusLogBuff[LOG_LEN] = {0x00};               //状态日志缓冲区
char SendLogBuff[LOG_LEN] = {0x00};                 //发包日志缓冲区
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)
            {
                RemoteIpStr = remote_endpoint.address().to_string();
                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);        // 转成本地时间
        t->tm_year+=1900;
        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)
            {
                memset(StatusLogBuff,0x00,LOG_LEN);
                sprintf(StatusLogBuff,"[%04d-%02d-%02d-%02d-%02d-%02d]:Get Core Status",t->tm_year
                                                                ,t->tm_mon
                                                                ,t->tm_wday
                                                                ,t->tm_hour
                                                                ,t->tm_min
                                                                ,t->tm_sec);
                logAdd(TimeBuff,StatusLogBuff);
            }
            CallBackCoreStatus(RxData, send_buffer);
            break;
        case PKG_CAN_STATUS:
            break;
        case PKG_TRANS_CAN:
            break;
        case PKG_CTRL_GET:
            //获取控制权限，收到哪个ip的包，哪个ip就属于主控，主控接收所有Core发送的报文
            if (SystemCall.logEn == ENABLE)
            {
                memset(StatusLogBuff,0x00,LOG_LEN);
                sprintf(StatusLogBuff,"[%04d-%02d-%02d-%02d-%02d-%02d]:Get Ctrl Access %s",t->tm_year
                                                                ,t->tm_mon
                                                                ,t->tm_wday
                                                                ,t->tm_hour
                                                                ,t->tm_min
                                                                ,t->tm_sec
                                                                ,RemoteIpStr.c_str());
                //还需要把ip加上
                logAdd(TimeBuff,StatusLogBuff);
            }
            memcpy(send_buffer,RxData,RECV_BUFFER_SIZE);
            break;
    }

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

    //回包
    UdpSendData(RemoteIpStr.c_str(), 12346, send_buffer, RECV_BUFFER_SIZE);

    //调试使能就记录一下，记录使用队列保证不影响收发
    if (SystemCall.logEn == ENABLE)
    {
        memset(SendLogBuff,0x00,LOG_LEN);
        sprintf(SendLogBuff,"[%04d-%02d-%02d-%02d-%02d-%02d]:Send Pkg ",t->tm_year
                                                        ,t->tm_mon
                                                        ,t->tm_wday
                                                        ,t->tm_hour
                                                        ,t->tm_min
                                                        ,t->tm_sec);
        char *p = &SendLogBuff[31];
        for (int i = 0; i < RECV_BUFFER_SIZE; i++) {
            p += sprintf(p, "0x%02X ", send_buffer[i]);  // ← 关键在这里
        }
       
        if (SystemCall.logEn == ENABLE)
        {
            logAdd(TimeBuff,SendLogBuff);
        }
    }
}

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;
    }

    return 1;
}

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