/**
 * @file    test_comm.cpp
 * @brief   通讯抽象层模块单元测试
 * @details 覆盖：生命周期、TCP 回环、UDP 回环、状态回调、
 *          断连重连、参数校验、错误处理。
 *          7 项测试，需要 comm_run 在独立线程中运行。
 */
#include "myComm.h"
#include "myBase.h"

#include <cstdio>
#include <cstring>
#include <cassert>
#include <thread>
#include <chrono>
#include <atomic>

/* ===== 测试辅助宏 ===== */

static int g_pass = 0;
static int g_fail = 0;

#define TEST(name) \
    do \
    { \
        printf("  TEST: %s ... ", name); \
    } while (0)

#define OK() \
    do \
    { \
        printf("OK\n"); \
        g_pass++; \
    } while (0)

#define FAIL(msg) \
    do \
    { \
        printf("FAIL: %s\n", msg); \
        g_fail++; \
    } while (0)

/* ===== 全局测试状态 ===== */

static std::thread            g_event_thread;
static std::atomic<bool>      g_test_running(false);

static int              g_svr_id   = -1;
static int              g_cli_id   = -1;
static int              g_udp1_id  = -1;
static int              g_udp2_id  = -1;
static int              g_svr_client_fd = -1;
static int              g_cli_local_fd  = -1;   /** 客户端本地 fd（从状态回调获取） */
static int              g_udp_cli_fd    = -1;   /** UDP 客户端 fd */

static int              g_recv_count    = 0;
static int              g_state_changes = 0;
static int              g_last_state    = -1;
static unsigned char    g_recv_buf[1024];
static int              g_recv_len = 0;

static int              g_svr_state_changes = 0;

/* ===== 回调函数 ===== */

static void on_cli_state(int id, int fd, int state)
{
    (void)id;
    g_cli_local_fd = fd;
    g_last_state = state;
    g_state_changes++;
}

static void on_svr_state(int id, int fd, int state)
{
    (void)id;
    (void)fd;
    (void)state;
    g_svr_state_changes++;
}

static void on_svr_recv(int id, int fd, const unsigned char *data, int len)
{
    (void)id;
    (void)fd;

    memcpy(g_recv_buf, data, len);
    g_recv_len = len;
    g_recv_count++;

    if (g_svr_client_fd < 0)
    {
        g_svr_client_fd = fd;
    }
}

static void on_udp_cli_state(int id, int fd, int state)
{
    (void)id;
    (void)state;
    g_udp_cli_fd = fd;
}

static void on_udp_recv(int id, int fd, const unsigned char *data, int len)
{
    (void)id;
    (void)fd;

    memcpy(g_recv_buf, data, len);
    g_recv_len = len;
    g_recv_count++;
}

/* ===== 辅助函数 ===== */

static void reset_test_state(void)
{
    g_recv_count      = 0;
    g_state_changes   = 0;
    g_last_state      = -1;
    g_svr_client_fd   = -1;
    g_cli_local_fd    = -1;
    g_udp_cli_fd      = -1;
    g_recv_len        = 0;
    g_svr_state_changes = 0;
    memset(g_recv_buf, 0, sizeof(g_recv_buf));
}

static void start_event_loop(void)
{
    g_test_running = true;
    g_event_thread = std::thread([]()
    {
        comm_run();
    });
}

static void stop_event_loop(void)
{
    comm_stop();
    if (g_event_thread.joinable())
    {
        g_event_thread.join();
    }
    g_test_running = false;
}

static void msleep(int ms)
{
    std::this_thread::sleep_for(std::chrono::milliseconds(ms));
}

/* ================================================================
 * 测试 1: 创建与销毁
 * ================================================================ */
static void test_01_create_destroy(void)
{
    TEST("create/destroy TCP server");
    {
        union_comm_para para;

        memset(&para, 0, sizeof(para));
        strcpy(para.tcp.local_ip, "127.0.0.1");
        para.tcp.local_port = 19999;

        int id = comm_create(COMM_TYPE_TCP_SERVER, 0, &para);

        if (id >= 0)
        {
            int ret = comm_destroy(id);

            if (ret == COMM_OK)
            {
                OK();
            }
            else
            {
                FAIL("destroy failed");
            }
        }
        else
        {
            FAIL("create failed");
        }
    }

    TEST("create/destroy TCP client");
    {
        union_comm_para para;

        memset(&para, 0, sizeof(para));
        strcpy(para.tcp.remote_ip, "127.0.0.1");
        para.tcp.remote_port = 19999;

        int id = comm_create(COMM_TYPE_TCP_CLIENT, 0, &para);

        if (id >= 0)
        {
            int ret = comm_destroy(id);

            if (ret == COMM_OK)
            {
                OK();
            }
            else
            {
                FAIL("destroy failed");
            }
        }
        else
        {
            FAIL("create failed");
        }
    }

    TEST("create/destroy UDP server");
    {
        union_comm_para para;

        memset(&para, 0, sizeof(para));
        strcpy(para.udp.local_ip, "127.0.0.1");
        para.udp.local_port = 20000;

        int id = comm_create(COMM_TYPE_UDP_SERVER, 0, &para);

        if (id >= 0)
        {
            int ret = comm_destroy(id);

            if (ret == COMM_OK)
            {
                OK();
            }
            else
            {
                FAIL("destroy failed");
            }
        }
        else
        {
            FAIL("create failed");
        }
    }

    TEST("create/destroy UDP client");
    {
        union_comm_para para;

        memset(&para, 0, sizeof(para));
        strcpy(para.udp.local_ip, "127.0.0.1");
        para.udp.local_port = 20001;
        strcpy(para.udp.remote_ip, "127.0.0.1");
        para.udp.remote_port = 20000;

        int id = comm_create(COMM_TYPE_UDP_CLIENT, 0, &para);

        if (id >= 0)
        {
            int ret = comm_destroy(id);

            if (ret == COMM_OK)
            {
                OK();
            }
            else
            {
                FAIL("destroy failed");
            }
        }
        else
        {
            FAIL("create failed");
        }
    }
}

/* ================================================================
 * 测试 2: 参数校验
 * ================================================================ */
static void test_02_param_validation(void)
{
    TEST("comm_create with NULL para");
    {
        int id = comm_create(COMM_TYPE_TCP_SERVER, 0, NULL);

        if (id == COMM_ERR_PARAM)
        {
            OK();
        }
        else
        {
            FAIL("expected COMM_ERR_PARAM");
        }
    }

    TEST("comm_create with invalid type");
    {
        union_comm_para para;

        memset(&para, 0, sizeof(para));

        int id = comm_create(-1, 0, &para);

        if (id == COMM_ERR_PARAM)
        {
            OK();
        }
        else
        {
            FAIL("expected COMM_ERR_PARAM");
        }
    }

    TEST("comm_create with out-of-range type");
    {
        union_comm_para para;

        memset(&para, 0, sizeof(para));

        int id = comm_create(99, 0, &para);

        if (id == COMM_ERR_PARAM)
        {
            OK();
        }
        else
        {
            FAIL("expected COMM_ERR_PARAM");
        }
    }

    TEST("comm_connect invalid id");
    {
        int ret = comm_connect(9999);

        if (ret == COMM_ERR_NOT_FOUND)
        {
            OK();
        }
        else
        {
            FAIL("expected COMM_ERR_NOT_FOUND");
        }
    }

    TEST("comm_send NULL data");
    {
        int ret = comm_send(1, 0, NULL, 5);

        if (ret == COMM_ERR_PARAM)
        {
            OK();
        }
        else
        {
            FAIL("expected COMM_ERR_PARAM");
        }
    }

    TEST("comm_send zero len");
    {
        unsigned char buf[4] = {0};

        int ret = comm_send(1, 0, buf, 0);

        if (ret == COMM_ERR_PARAM)
        {
            OK();
        }
        else
        {
            FAIL("expected COMM_ERR_PARAM");
        }
    }

    TEST("comm_destroy invalid id");
    {
        int ret = comm_destroy(9999);

        if (ret == COMM_ERR_NOT_FOUND)
        {
            OK();
        }
        else
        {
            FAIL("expected COMM_ERR_NOT_FOUND");
        }
    }
}

/* ================================================================
 * 测试 3: TCP 回环 — 客户端发送，服务器接收
 * ================================================================ */
static void test_03_tcp_loopback(void)
{
    TEST("TCP loopback send/recv");
    {
        reset_test_state();

        /* 创建 TCP 服务器 */
        union_comm_para svr_para;

        memset(&svr_para, 0, sizeof(svr_para));
        strcpy(svr_para.tcp.local_ip, "127.0.0.1");
        svr_para.tcp.local_port = 21001;

        g_svr_id = comm_create(COMM_TYPE_TCP_SERVER, 0, &svr_para);
        if (g_svr_id < 0)
        {
            FAIL("server create failed");
            return;
        }

        comm_recv_register(g_svr_id, on_svr_recv);
        comm_state_register(g_svr_id, on_svr_state);

        if (comm_connect(g_svr_id) != COMM_OK)
        {
            FAIL("server connect failed");
            comm_destroy(g_svr_id);
            return;
        }

        /* 创建 TCP 客户端 */
        union_comm_para cli_para;

        memset(&cli_para, 0, sizeof(cli_para));
        strcpy(cli_para.tcp.remote_ip, "127.0.0.1");
        cli_para.tcp.remote_port = 21001;

        g_cli_id = comm_create(COMM_TYPE_TCP_CLIENT, 0, &cli_para);
        if (g_cli_id < 0)
        {
            FAIL("client create failed");
            comm_destroy(g_svr_id);
            return;
        }

        comm_state_register(g_cli_id, on_cli_state);

        if (comm_connect(g_cli_id) != COMM_OK)
        {
            FAIL("client connect failed");
            comm_destroy(g_cli_id);
            comm_destroy(g_svr_id);
            return;
        }

        /* 等待连接建立 + accept */
        msleep(500);

        if (g_state_changes == 0 || g_cli_local_fd < 0)
        {
            printf("(state_changes=%d cli_fd=%d svr_states=%d) ",
                   g_state_changes, g_cli_local_fd, g_svr_state_changes);
            FAIL("no state change on client connect");
            comm_destroy(g_cli_id);
            comm_destroy(g_svr_id);
            return;
        }

        /* 发送数据 */
        const char *msg = "HELLO_MODBUS";
        int         len = (int)strlen(msg);

        {
            int sent = comm_send(g_cli_id, g_cli_local_fd,
                                 (const unsigned char *)msg, len);

            if (sent != len)
            {
                printf("(sent=%d expected=%d errno=%d svr_states=%d) ",
                       sent, len, errno, g_svr_state_changes);
                FAIL("send failed or partial");
                comm_destroy(g_cli_id);
                comm_destroy(g_svr_id);
                return;
            }
        }

        /* 等待服务器接收（重试最多 2 秒） */
        for (int retry = 0; retry < 20 && g_recv_count == 0; retry++)
        {
            msleep(100);
        }

        if (g_recv_count > 0 && g_recv_len == len
            && memcmp(g_recv_buf, msg, len) == 0)
        {
            OK();
        }
        else
        {
            printf("recv_count=%d recv_len=%d expected_len=%d svr_states=%d cli_states=%d ",
                   g_recv_count, g_recv_len, len,
                   g_svr_state_changes, g_state_changes);
            FAIL("data mismatch or not received");
        }

        comm_destroy(g_cli_id);
        comm_destroy(g_svr_id);
    }
}

/* ================================================================
 * 测试 4: UDP 回环
 * ================================================================ */
static void test_04_udp_loopback(void)
{
    TEST("UDP loopback send/recv");
    {
        reset_test_state();

        /* 创建 UDP 服务器（接收端） */
        union_comm_para svr_para;

        memset(&svr_para, 0, sizeof(svr_para));
        strcpy(svr_para.udp.local_ip, "127.0.0.1");
        svr_para.udp.local_port = 22001;

        g_udp1_id = comm_create(COMM_TYPE_UDP_SERVER, 0, &svr_para);
        if (g_udp1_id < 0)
        {
            FAIL("UDP server create failed");
            return;
        }

        comm_recv_register(g_udp1_id, on_udp_recv);

        if (comm_connect(g_udp1_id) != COMM_OK)
        {
            FAIL("UDP server connect failed");
            comm_destroy(g_udp1_id);
            return;
        }

        /* 创建 UDP 客户端（发送端） */
        union_comm_para cli_para;

        memset(&cli_para, 0, sizeof(cli_para));
        strcpy(cli_para.udp.local_ip, "127.0.0.1");
        cli_para.udp.local_port = 22002;
        strcpy(cli_para.udp.remote_ip, "127.0.0.1");
        cli_para.udp.remote_port = 22001;

        g_udp2_id = comm_create(COMM_TYPE_UDP_CLIENT, 0, &cli_para);
        if (g_udp2_id < 0)
        {
            FAIL("UDP client create failed");
            comm_destroy(g_udp1_id);
            return;
        }

        comm_state_register(g_udp2_id, on_udp_cli_state);

        if (comm_connect(g_udp2_id) != COMM_OK)
        {
            FAIL("UDP client connect failed");
            comm_destroy(g_udp2_id);
            comm_destroy(g_udp1_id);
            return;
        }

        msleep(200);

        if (g_udp_cli_fd < 0)
        {
            FAIL("UDP client fd not captured");
            comm_destroy(g_udp2_id);
            comm_destroy(g_udp1_id);
            return;
        }

        /* 发送数据 */
        const char *msg = "HELLO_UDP";
        int         len = (int)strlen(msg);

        {
            int sent = comm_send(g_udp2_id, g_udp_cli_fd,
                                 (const unsigned char *)msg, len);

            if (sent != len)
            {
                printf("(sent=%d expected=%d) ", sent, len);
                FAIL("UDP send failed");
                comm_destroy(g_udp2_id);
                comm_destroy(g_udp1_id);
                return;
            }
        }

        /* 等待 UDP 接收（重试最多 2 秒） */
        for (int retry = 0; retry < 20 && g_recv_count == 0; retry++)
        {
            msleep(100);
        }

        if (g_recv_count > 0 && g_recv_len == len
            && memcmp(g_recv_buf, msg, len) == 0)
        {
            OK();
        }
        else
        {
            printf("recv_count=%d recv_len=%d expected_len=%d ",
                   g_recv_count, g_recv_len, len);
            FAIL("UDP data mismatch or not received");
        }

        comm_destroy(g_udp2_id);
        comm_destroy(g_udp1_id);
    }
}

/* ================================================================
 * 测试 5: 状态回调
 * ================================================================ */
static void test_05_state_callbacks(void)
{
    TEST("state change callbacks (connected)");
    {
        reset_test_state();

        union_comm_para para;

        memset(&para, 0, sizeof(para));
        strcpy(para.tcp.local_ip, "127.0.0.1");
        para.tcp.local_port = 23001;

        int id = comm_create(COMM_TYPE_TCP_SERVER, 0, &para);

        if (id < 0)
        {
            FAIL("create failed");
            return;
        }

        comm_state_register(id, on_svr_state);

        int ret = comm_connect(id);

        if (ret != COMM_OK)
        {
            FAIL("connect failed");
            comm_destroy(id);
            return;
        }

        msleep(50);

        if (g_svr_state_changes > 0)
        {
            OK();
        }
        else
        {
            FAIL("no state callback received");
        }

        comm_destroy(id);
    }

    TEST("state change callbacks (disconnect)");
    {
        reset_test_state();

        union_comm_para para;

        memset(&para, 0, sizeof(para));
        strcpy(para.udp.local_ip, "127.0.0.1");
        para.udp.local_port = 23002;

        int id = comm_create(COMM_TYPE_UDP_SERVER, 0, &para);

        if (id < 0)
        {
            FAIL("create failed");
            return;
        }

        comm_state_register(id, on_svr_state);
        comm_connect(id);

        msleep(50);

        comm_disconnect(id);

        msleep(50);

        /* UDP 不触发 DISCONNECT（非面向连接） */
        /* 故测试 TCP */
        if (g_svr_state_changes > 0)
        {
            OK();
        }
        else
        {
            /* UDP connect也会触发 CONNECTED 状态 */
            FAIL("no state callback");
        }

        comm_destroy(id);
    }
}

/* ================================================================
 * 测试 6: 未连接发送
 * ================================================================ */
static void test_06_send_without_connect(void)
{
    TEST("send without connect should fail");
    {
        reset_test_state();

        union_comm_para para;

        memset(&para, 0, sizeof(para));
        strcpy(para.tcp.remote_ip, "127.0.0.1");
        para.tcp.remote_port = 24001;

        int id = comm_create(COMM_TYPE_TCP_CLIENT, 0, &para);

        if (id < 0)
        {
            /* 创建应该是 OK 的，不需要连接 */
            FAIL("create failed");
            return;
        }

        const char *msg = "test";
        int         ret = comm_send(id, -1, (const unsigned char *)msg,
                                    (int)strlen(msg));

        /* 未连接的情况下，fd 无效，send 应该失败 */
        if (ret < 0)
        {
            OK();
        }
        else
        {
            FAIL("send should have failed without connect");
        }

        comm_destroy(id);
    }
}

/* ================================================================
 * 测试 7: 断开重连
 * ================================================================ */
static void test_07_disconnect_reconnect(void)
{
    TEST("disconnect + reconnect cycle");
    {
        reset_test_state();

        union_comm_para para;

        memset(&para, 0, sizeof(para));
        strcpy(para.udp.local_ip, "127.0.0.1");
        para.udp.local_port = 25001;

        int id = comm_create(COMM_TYPE_UDP_SERVER, 0, &para);

        if (id < 0)
        {
            FAIL("create failed");
            return;
        }

        /* 第一次连接 */
        if (comm_connect(id) != COMM_OK)
        {
            FAIL("first connect failed");
            comm_destroy(id);
            return;
        }

        /* 断开 */
        if (comm_disconnect(id) != COMM_OK)
        {
            FAIL("disconnect failed");
            comm_destroy(id);
            return;
        }

        /* 第二次连接 */
        if (comm_connect(id) != COMM_OK)
        {
            FAIL("second connect failed");
            comm_destroy(id);
            return;
        }

        OK();

        comm_destroy(id);
    }
}

/* ================================================================
 * main
 * ================================================================ */
int main(void)
{
    printf("\n=== libcomm 单元测试 ===\n\n");

    /* 启动事件循环（comm_run 自初始化 epoll，无需预创建实例） */
    printf("[启动 epoll 事件循环]\n");
    start_event_loop();
    msleep(50);

    /* 1. 创建与销毁 */
    printf("\n[1] 创建与销毁 (4 项)\n");
    test_01_create_destroy();

    /* 2. 参数校验 */
    printf("\n[2] 参数校验 (7 项)\n");
    test_02_param_validation();

    /* 3. TCP 回环 */
    printf("\n[3] TCP 回环\n");
    test_03_tcp_loopback();

    /* 4. UDP 回环 */
    printf("\n[4] UDP 回环\n");
    test_04_udp_loopback();

    /* 5. 状态回调 */
    printf("\n[5] 状态回调 (2 项)\n");
    test_05_state_callbacks();

    /* 6. 未连接发送 */
    printf("\n[6] 错误路径\n");
    test_06_send_without_connect();

    /* 7. 断开重连 */
    printf("\n[7] 断开重连\n");
    test_07_disconnect_reconnect();

    /* 停止事件循环 */
    printf("\n[停止 epoll 事件循环]\n");
    stop_event_loop();

    /* 结果汇总 */
    printf("\n========================================\n");
    printf("  测试结果: %d pass, %d fail\n", g_pass, g_fail);
    printf("========================================\n");

    return (g_fail > 0) ? 1 : 0;
}
