
#include <netinet/in.h>
#include <stdatomic.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/epoll.h>
// #include "../common.h"
#include <bits/types/struct_timeval.h>
#include <pthread.h>
#include <sys/epoll.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/syslog.h>
#include <unistd.h>
#include "frpc_proxy.h"
#include "tcp_server.h"
#include "../proto_forward.h"

extern void channel_lock(channel_t* channel);
extern void channel_unlock(channel_t* channel);
extern int  read_data_timeout(int fd, unsigned char* buff, int buffsize, int timeout);
extern int write_bin_data(char* buffer, int len, FILE* log, bool tx);

typedef struct modbus_tcp_header_t
{
    uint16_t transaction_id;
    uint16_t protocol_id;
    uint16_t length;
} modbus_tcp_header_t;

// TCP转RTU函数
int tcp_to_rtu(const char* tcp_frame, modbus_tcp_header_t* header, char* rtu_frame, int tcp_len)
{
    if (tcp_len < 7)  // 最小TCP报文长度检查
    {
        ems_syslog(LOG_WARNING, "tcp to rtu error! tcp_len=%d", tcp_len);
        return -1;
    }
    // 解析TCP头
    header->transaction_id = ntohs(*(uint16_t*)(tcp_frame));
    header->protocol_id = ntohs(*(uint16_t*)(tcp_frame + 2));
    header->length = ntohs(*(uint16_t*)(tcp_frame + 4));
    
    // 检查协议ID和长度
    if (header->protocol_id != 0 || header->length != tcp_len - 6) 
    {
        ems_syslog(LOG_WARNING, "tcp to rtu error! protocol_id=%d, length=%d, tcp_len=%d", header->protocol_id, header->length, tcp_len);
        return -1; 
    }

    // 跳过TCP头(7字节)，复制数据部分
    memcpy(rtu_frame, tcp_frame + 6, header->length);
    
    // 计算RTU CRC (需要实现crc16_modbus函数)
    uint16_t crc = crc16((uint8_t*)rtu_frame, header->length);
    rtu_frame[header->length] =(crc >> 8) & 0xFF;
    rtu_frame[header->length + 1] =  crc & 0xFF;
    
    return header->length + 2; // 返回RTU帧长度
}

// RTU转TCP函数
int rtu_to_tcp(const char* rtu_frame, int rtu_len, modbus_tcp_header_t* header, char* tcp_frame)
{
    if (rtu_len < 4) return -1; // 最小RTU报文长度检查

    // 设置TCP头
    uint16_t transaction_id = htons(header->transaction_id);
    uint16_t protocol_id    = htons(header->protocol_id);
    uint16_t length         = htons(rtu_len - 2);

    // 复制TCP头
    memcpy(tcp_frame, &transaction_id, 2);
    memcpy(tcp_frame + 2, &protocol_id, sizeof(protocol_id));
    memcpy(tcp_frame + 4, &length, 2);

    // 复制数据部分(去掉CRC)
    memcpy(tcp_frame + 6, rtu_frame, rtu_len - 2);

    return 4 + rtu_len; // 返回TCP帧长度
}

// 帧模式 支持多个连接,报文需要解析
static int tcp2rtu_write_and_read_dev_no(tcp_trans_t* cfg, char* buffer, int len, FILE* log)
{
    if (cfg == NULL || cfg->chan_pr == NULL || buffer == NULL || len <= 0) return -1;
    int        ret     = -1;
    channel_t* chan_pr = cfg->chan_pr;

    // 解析modbus tcp 报文
    char rtu_buffer[512] = {0};
    modbus_tcp_header_t header = {0};

    char temp[512] = {0};
    for (int i = 0; i < len && i < 128; i++)
    {
        snprintf(temp + i * 3, 4, "%02x ", buffer[i]);
    }
    proto_syslog(LOG_WARNING, "dev_no[%s] recv len:%d,  data: %s", cfg->chan_pr->channel, len, temp);

    int rtu_len = tcp_to_rtu(buffer, &header, rtu_buffer, len);
    if (rtu_len <= 0)
    {
        proto_syslog(LOG_ERR, "dev_no[%s] tcp to rtu error!, len=%d", cfg->chan_pr->channel, rtu_len);
        return -1;
    }

    for (int i = 0; i < rtu_len && i < 128; i++)
    {
        snprintf(temp + i * 3, 4, "%02x ", rtu_buffer[i]);
    }
    proto_syslog(LOG_WARNING, "dev_no[%s] recv len:%d,  data: %s", cfg->chan_pr->channel, rtu_len, temp);

    channel_lock(chan_pr);
    if (chan_pr->s > 0)
    {
        int ret = write(chan_pr->s, rtu_buffer, rtu_len);
        if (ret <= 0)
        {
            proto_syslog(LOG_ERR, "dev_no[%s] send data error!", cfg->chan_pr->channel);
            ret = -2;
        }
        else
        {
            write_bin_data(rtu_buffer, rtu_len, log, true);
            int l = read_data_timeout(chan_pr->s, (unsigned char*)rtu_buffer, 512, cfg->timeout);
            if (l < 0)
            {
                proto_syslog(LOG_WARNING, "dev_no[%s] write to dev error!", cfg->chan_pr->channel);
                ret = -1;
            }
            else if( l == 0)
            {
                proto_syslog(LOG_WARNING, "dev_no[%s] read from dev timeout!", cfg->chan_pr->channel);
            }
            else
            {
                for (int i = 0; i < l && i < 128; i++)
                {
                    snprintf(temp + i * 3, 4, "%02x ", rtu_buffer[i]);
                }
                proto_syslog(LOG_WARNING, "dev_no[%s] recv len:%d,  data: %s", cfg->chan_pr->channel, l, temp);

                write_bin_data(rtu_buffer, l, log, false);
                ret = rtu_to_tcp(rtu_buffer, l, &header, buffer);
                if (ret < 0)
                {
                    proto_syslog(LOG_WARNING, "dev_no[%s] rtu to tcp error!", cfg->chan_pr->channel);
                }
            }
        }
    }
    else
    {
        proto_syslog(LOG_ERR, "dev_no[%s] cfg->chan_pr->channel is NULL !", cfg->chan_pr->channel);
        ret = -2;
    }
    channel_unlock(chan_pr);
    return ret;
}
void* tcp_server_tcp2rtu_task(void* arg)
{
    tcp_trans_t* tcp = (tcp_trans_t*)arg;
    if (tcp == NULL || tcp->sfd < 0)
    {
        ems_syslog(LOG_ERR, "proxy_server cfg error");
        goto END;
    }

    tcp->epfd = epoll_create1(0);
    if (tcp->epfd < 0)
    {
        ems_syslog(LOG_ERR, "epoll_create1 error: %s", strerror(errno));
        goto END;
    }

    struct epoll_event ev, events[10];
    ev.events  = EPOLLIN;
    ev.data.fd = tcp->sfd;
    if (epoll_ctl(tcp->epfd, EPOLL_CTL_ADD, tcp->sfd, &ev) < 0)
    {
        ems_syslog(LOG_ERR, "epoll_ctl error: %s", strerror(errno));
        goto END;
    }

    char buffer[4096] = {0};
    atomic_store(&tcp->state, FRPC_SERVER_RUNNING);

    while (atomic_load(&tcp->state) < FRPC_SERVER_STOPING)
    {
        int nfds = epoll_wait(tcp->epfd, events, 10, 1000);
        if (nfds < 0)
        {
            ems_syslog(LOG_NOTICE, "epoll_wait error: %s", strerror(errno));
            continue;
        }
        for (int i = 0; i < nfds; i++)
        {
            if (events[i].data.fd == tcp->sfd)
            {
                int cfd = accept(tcp->sfd, NULL, NULL);
                if (cfd < 0)
                {
                    ems_syslog(LOG_NOTICE, "accept error: %s", strerror(errno));
                    continue;
                }
                ev.events  = EPOLLIN;
                ev.data.fd = cfd;
                if (epoll_ctl(tcp->epfd, EPOLL_CTL_ADD, cfd, &ev) < 0)
                {
                    ems_syslog(LOG_NOTICE, "epoll_ctl error: %s", strerror(errno));
                    close(cfd);
                    continue;
                }
            }
            else
            {
                int len = read(events[i].data.fd, buffer, sizeof(buffer));
                if (len <= 0)
                {
                    ems_syslog(LOG_INFO, "client close!");
                    close(events[i].data.fd);
                    continue;
                }
                else
                {
                    int l = tcp2rtu_write_and_read_dev_no(tcp, buffer, len, tcp->log_fp);
                    if (l > 0)
                    {
                        write(events[i].data.fd, buffer, l);
                    }
                    else if (l < 0)
                    {
                        ems_syslog(LOG_NOTICE, "write_and_read_dev_no error: %d", l);
                    }
                }
            }
        }
    }

END:
    if (tcp->sfd > 0)
    {
        close(tcp->sfd);
        tcp->sfd = -1;
    }
    if (tcp->epfd > 0)
    {
        close(tcp->epfd);
        tcp->epfd = -1;
    }
    atomic_store(&tcp->state, FRPC_SERVER_STOPED);
    return NULL;
}
