/**
 * @file    comm_core.cpp
 * @brief   通讯抽象层 — 核心模块
 * @details 全局变量定义、epoll 工具函数、事件循环主循环、
 *          comm_create/connect/disconnect/destroy/run/stop 实现。
 */

#include "comm_internal.h"

#include <sys/eventfd.h>

/* === 全局变量定义 === */
std::map<int, stru_comm_instance *> g_instances;
std::map<int, stru_comm_fd_info>    g_fd_map;
std::mutex        g_mutex;
std::atomic<bool> g_running(false);
int               g_epoll_fd       = -1;
int               g_next_id        = 1;
int               g_stop_event_fd  = -1;

/* ================================================================
 * 工具函数
 * ================================================================ */

/**
 * @brief 初始化 epoll + eventfd（幂等，可重复调用）
 * @return COMM_OK 成功, COMM_ERR_INTERNAL 失败
 */
int comm_epoll_init(void)
{
    if (g_epoll_fd != -1)
    {
        return COMM_OK;     /* 已初始化 */
    }

    g_epoll_fd = epoll_create1(0);
    if (g_epoll_fd == -1)
    {
        return COMM_ERR_INTERNAL;
    }

    g_stop_event_fd = eventfd(0, EFD_NONBLOCK);
    if (g_stop_event_fd == -1)
    {
        close(g_epoll_fd);
        g_epoll_fd = -1;

        return COMM_ERR_INTERNAL;
    }

    struct epoll_event ev;

    memset(&ev, 0, sizeof(ev));
    ev.events  = EPOLLIN;
    ev.data.fd = g_stop_event_fd;
    epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, g_stop_event_fd, &ev);

    return COMM_OK;
}

/**
 * @brief 设置 fd 为非阻塞模式
 */
int set_nonblock(int fd)
{
    int flags = fcntl(fd, F_GETFL, 0);

    if (flags == -1)
    {
        return -1;
    }

    return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}

/**
 * @brief 向 epoll 添加 fd
 */
int epoll_add_fd(int fd, int instance_id, int is_listen)
{
    struct epoll_event ev;

    memset(&ev, 0, sizeof(ev));
    ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLRDHUP;
    ev.data.fd = fd;

    if (epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1)
    {
        return -1;
    }

    stru_comm_fd_info info;

    info.fd          = fd;
    info.is_listen   = is_listen;
    info.instance_id = instance_id;
    g_fd_map[fd]     = info;

    return 0;
}

/**
 * @brief 从 epoll 移除 fd
 */
int epoll_del_fd(int fd)
{
    epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, fd, NULL);
    g_fd_map.erase(fd);

    return 0;
}

/**
 * @brief 通知状态变化
 */
void notify_state(stru_comm_instance *inst, int fd, int state)
{
    inst->state = state;

    if (inst->state_cb)
    {
        inst->state_cb(inst->id, fd, state);
    }
}

/**
 * @brief 关闭客户端 fd 并清理
 */
void close_client_fd(stru_comm_instance *inst, int fd)
{
    epoll_del_fd(fd);
    close(fd);

    notify_state(inst, fd, COMM_STATE_DISCONNECTED);

    /* 从 client_fds 中移除 */
    for (size_t i = 0; i < inst->client_fds.size(); i++)
    {
        if (inst->client_fds[i] == fd)
        {
            inst->client_fds.erase(inst->client_fds.begin() + (long)i);
            break;
        }
    }
}

/**
 * @brief 处理可写事件（TCP 客户端连接完成）
 */
void handle_write(int fd)
{
    struct epoll_event ev;

    memset(&ev, 0, sizeof(ev));
    ev.events  = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLRDHUP;
    ev.data.fd = fd;
    epoll_ctl(g_epoll_fd, EPOLL_CTL_MOD, fd, &ev);
}

/**
 * @brief 处理错误事件
 */
void handle_error(stru_comm_instance *inst, int fd)
{
    int       error = 0;
    socklen_t len   = sizeof(error);

    getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len);

    if (inst->debug)
    {
        LOG_E("comm[%d] fd=%d error: %s", inst->id, fd, strerror(error));
    }

    notify_state(inst, fd, COMM_STATE_ERROR);
}

/* ================================================================
 * TCP 数据读取
 * ================================================================ */

/**
 * @brief 处理 TCP 可读事件
 */
LOCAL void handle_tcp_read(stru_comm_instance *inst, int fd)
{
    unsigned char buf[COMM_RECV_BUF_SIZE];

    while (1)
    {
        ssize_t n = recv(fd, buf, sizeof(buf), 0);

        if (n > 0)
        {
            if (inst->recv_cb)
            {
                inst->recv_cb(inst->id, fd, buf, (int)n);
            }
        }
        else if (n == 0)
        {
            if (inst->debug)
            {
                LOG_I("comm[%d] fd=%d connection closed by peer", inst->id, fd);
            }
            close_client_fd(inst, fd);
            break;
        }
        else
        {
            if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                break;
            }

            if (errno != EINTR)
            {
                if (inst->debug)
                {
                    LOG_E("comm[%d] fd=%d recv error: %s", inst->id, fd, strerror(errno));
                }
                close_client_fd(inst, fd);
            }
            break;
        }
    }
}

/* ================================================================
 * 事件循环
 * ================================================================ */

/**
 * @brief epoll 事件循环工作函数
 */
LOCAL void worker_loop(void)
{
    struct epoll_event events[COMM_MAX_EVENTS];

    while (g_running)
    {
        int nfds = epoll_wait(g_epoll_fd, events, COMM_MAX_EVENTS, 100);

        if (nfds == -1)
        {
            if (errno == EINTR)
            {
                continue;
            }
            break;
        }

        for (int i = 0; i < nfds; i++)
        {
            int fd = events[i].data.fd;

            /* 停止事件 */
            if (fd == g_stop_event_fd)
            {
                g_running = false;
                break;
            }

            std::lock_guard<std::mutex> lock(g_mutex);

            /* 查找 fd 对应信息 */
            auto it = g_fd_map.find(fd);
            if (it == g_fd_map.end())
            {
                continue;
            }

            int inst_id   = it->second.instance_id;
            int is_listen = it->second.is_listen;

            auto inst_it = g_instances.find(inst_id);
            if (inst_it == g_instances.end())
            {
                continue;
            }

            stru_comm_instance *inst = inst_it->second;

            /* 错误/挂起 */
            if (events[i].events & (EPOLLERR | EPOLLHUP | EPOLLRDHUP))
            {
                if (is_listen)
                {
                    handle_error(inst, fd);
                }
                else
                {
                    handle_error(inst, fd);
                    close_client_fd(inst, fd);
                }
                continue;
            }

            /* 可写（TCP 客户端连接完成） */
            if (events[i].events & EPOLLOUT)
            {
                int       error = 0;
                socklen_t len   = sizeof(error);

                getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len);

                if (error == 0)
                {
                    handle_write(fd);
                    notify_state(inst, fd, COMM_STATE_CONNECTED);

                    if (inst->debug)
                    {
                        LOG_I("comm[%d] TCP client connected fd=%d", inst->id, fd);
                    }
                }
                else
                {
                    if (inst->debug)
                    {
                        LOG_E("comm[%d] TCP connect failed: %s", inst->id, strerror(error));
                    }
                    epoll_del_fd(fd);
                    close(fd);
                    inst->local_fd = -1;
                    notify_state(inst, -1, COMM_STATE_ERROR);
                }
                continue;
            }

            /* 可读 */
            if (events[i].events & EPOLLIN)
            {
                if (is_listen)
                {
                    handle_accept(inst);
                }
                else if (inst->type == COMM_TYPE_UDP_SERVER || inst->type == COMM_TYPE_UDP_CLIENT)
                {
                    handle_udp_read(inst, fd);
                }
                else if (inst->type == COMM_TYPE_UART)
                {
                    handle_uart_read(inst, fd);
                }
                else
                {
                    handle_tcp_read(inst, fd);
                }
            }
        }
    }
}

/* ================================================================
 * 对外 C 接口
 * ================================================================ */

/**
 * @brief 创建通讯实例
 */
int comm_create(int type, int debug, const union_comm_para *para)
{
    if (!para)
    {
        return COMM_ERR_PARAM;
    }

    if (type < COMM_TYPE_TCP_SERVER || type > COMM_TYPE_UART)
    {
        return COMM_ERR_PARAM;
    }

    std::lock_guard<std::mutex> lock(g_mutex);

    /* 惰性初始化 epoll */
    int ret = comm_epoll_init();

    if (ret != COMM_OK)
    {
        return ret;
    }

    stru_comm_instance *inst = new stru_comm_instance();

    if (!inst)
    {
        return COMM_ERR_MEM;
    }

    inst->id         = g_next_id++;
    inst->type       = type;
    inst->debug      = debug;
    inst->state      = COMM_STATE_DISCONNECTED;
    inst->listen_fd  = -1;
    inst->local_fd   = -1;
    inst->recv_cb    = NULL;
    inst->state_cb   = NULL;

    /* 拷贝参数 */
    switch (type)
    {
    case COMM_TYPE_TCP_SERVER:
        strncpy(inst->local_ip, para->tcp.local_ip, sizeof(inst->local_ip) - 1);
        inst->local_port = para->tcp.local_port;
        break;

    case COMM_TYPE_TCP_CLIENT:
        strncpy(inst->local_ip, para->tcp.local_ip, sizeof(inst->local_ip) - 1);
        inst->local_port  = para->tcp.local_port;
        strncpy(inst->remote_ip, para->tcp.remote_ip, sizeof(inst->remote_ip) - 1);
        inst->remote_port = para->tcp.remote_port;
        break;

    case COMM_TYPE_UDP_SERVER:
        strncpy(inst->local_ip, para->udp.local_ip, sizeof(inst->local_ip) - 1);
        inst->local_port = para->udp.local_port;
        break;

    case COMM_TYPE_UDP_CLIENT:
        strncpy(inst->local_ip, para->udp.local_ip, sizeof(inst->local_ip) - 1);
        inst->local_port  = para->udp.local_port;
        strncpy(inst->remote_ip, para->udp.remote_ip, sizeof(inst->remote_ip) - 1);
        inst->remote_port = para->udp.remote_port;
        break;

    case COMM_TYPE_UART:
        strncpy(inst->uart_device, para->uart.device, sizeof(inst->uart_device) - 1);
        inst->uart_baudrate  = para->uart.baudrate;
        inst->uart_data_bits = para->uart.data_bits;
        inst->uart_stop_bits = para->uart.stop_bits;
        inst->uart_parity    = para->uart.parity;
        break;
    }

    g_instances[inst->id] = inst;

    if (debug)
    {
        LOG_I("comm[%d] created type=%d", inst->id, type);
    }

    return inst->id;
}

/**
 * @brief 建立连接
 */
int comm_connect(int id)
{
    std::lock_guard<std::mutex> lock(g_mutex);

    auto it = g_instances.find(id);
    if (it == g_instances.end())
    {
        return COMM_ERR_NOT_FOUND;
    }

    stru_comm_instance *inst = it->second;
    int                 ret  = COMM_OK;

    switch (inst->type)
    {
    case COMM_TYPE_TCP_SERVER:
        ret = tcp_server_bind(inst);
        if (ret == COMM_OK)
        {
            notify_state(inst, inst->listen_fd, COMM_STATE_CONNECTED);
        }
        break;

    case COMM_TYPE_TCP_CLIENT:
        ret = tcp_client_connect(inst);
        break;

    case COMM_TYPE_UDP_SERVER:
    case COMM_TYPE_UDP_CLIENT:
        ret = udp_bind(inst);
        if (ret == COMM_OK)
        {
            notify_state(inst, inst->local_fd, COMM_STATE_CONNECTED);
        }
        break;

    case COMM_TYPE_UART:
        ret = uart_open(inst);
        if (ret == COMM_OK)
        {
            notify_state(inst, inst->local_fd, COMM_STATE_CONNECTED);
        }
        break;

    default:
        ret = COMM_ERR_PARAM;
        break;
    }

    return ret;
}

/**
 * @brief 断开连接
 */
int comm_disconnect(int id)
{
    std::lock_guard<std::mutex> lock(g_mutex);

    auto it = g_instances.find(id);
    if (it == g_instances.end())
    {
        return COMM_ERR_NOT_FOUND;
    }

    stru_comm_instance *inst = it->second;

    /* 关闭所有客户端 fd */
    for (size_t i = 0; i < inst->client_fds.size(); i++)
    {
        int fd = inst->client_fds[i];

        epoll_del_fd(fd);
        close(fd);
        notify_state(inst, fd, COMM_STATE_DISCONNECTED);
    }
    inst->client_fds.clear();

    /* 关闭监听 fd */
    if (inst->listen_fd != -1)
    {
        epoll_del_fd(inst->listen_fd);
        close(inst->listen_fd);
        inst->listen_fd = -1;
    }

    /* 关闭本地 fd */
    if (inst->local_fd != -1)
    {
        if (inst->type == COMM_TYPE_UART)
        {
            uart_close(inst);
        }
        else
        {
            epoll_del_fd(inst->local_fd);
            close(inst->local_fd);
        }
        inst->local_fd = -1;
    }

    inst->state = COMM_STATE_DISCONNECTED;

    if (inst->debug)
    {
        LOG_I("comm[%d] disconnected", inst->id);
    }

    return COMM_OK;
}

/**
 * @brief 发送数据
 */
int comm_send(int id, int fd, const unsigned char *data, int len)
{
    if (!data || len <= 0)
    {
        return COMM_ERR_PARAM;
    }

    std::lock_guard<std::mutex> lock(g_mutex);

    auto it = g_instances.find(id);
    if (it == g_instances.end())
    {
        return COMM_ERR_NOT_FOUND;
    }

    stru_comm_instance *inst = it->second;

    /* UDP 客户端使用 sendto */
    if (inst->type == COMM_TYPE_UDP_CLIENT)
    {
        return udp_sendto(inst, fd, data, len);
    }

    ssize_t sent = send(fd, data, len, MSG_NOSIGNAL);

    if (sent == -1)
    {
        if (errno == EAGAIN || errno == EWOULDBLOCK)
        {
            return COMM_ERR_SEND;
        }

        if (inst->debug)
        {
            LOG_E("comm[%d] fd=%d send error: %s", inst->id, fd, strerror(errno));
        }

        return COMM_ERR_SEND;
    }

    return (int)sent;
}

/**
 * @brief 注册接收回调
 */
int comm_recv_register(int id, comm_recv_cb cb)
{
    std::lock_guard<std::mutex> lock(g_mutex);

    auto it = g_instances.find(id);
    if (it == g_instances.end())
    {
        return COMM_ERR_NOT_FOUND;
    }

    it->second->recv_cb = cb;

    return COMM_OK;
}

/**
 * @brief 注册状态回调
 */
int comm_state_register(int id, comm_state_cb cb)
{
    std::lock_guard<std::mutex> lock(g_mutex);

    auto it = g_instances.find(id);
    if (it == g_instances.end())
    {
        return COMM_ERR_NOT_FOUND;
    }

    it->second->state_cb = cb;

    return COMM_OK;
}

/**
 * @brief 销毁通讯实例
 */
int comm_destroy(int id)
{
    std::lock_guard<std::mutex> lock(g_mutex);

    auto it = g_instances.find(id);
    if (it == g_instances.end())
    {
        return COMM_ERR_NOT_FOUND;
    }

    stru_comm_instance *inst = it->second;

    /* 先断开所有连接 */
    for (size_t i = 0; i < inst->client_fds.size(); i++)
    {
        epoll_del_fd(inst->client_fds[i]);
        close(inst->client_fds[i]);
    }
    inst->client_fds.clear();

    if (inst->listen_fd != -1)
    {
        epoll_del_fd(inst->listen_fd);
        close(inst->listen_fd);
    }

    if (inst->local_fd != -1)
    {
        if (inst->type == COMM_TYPE_UART)
        {
            uart_close(inst);
        }
        else
        {
            epoll_del_fd(inst->local_fd);
            close(inst->local_fd);
        }
    }

    g_instances.erase(it);
    delete inst;

    return COMM_OK;
}

/**
 * @brief 启动事件循环（阻塞调用）
 */
int comm_run(void)
{
    /* 自初始化 epoll（不依赖 comm_create） */
    int ret = comm_epoll_init();

    if (ret != COMM_OK)
    {
        return ret;
    }

    g_running = true;
    worker_loop();
    g_running = false;

    return COMM_OK;
}

/**
 * @brief 停止事件循环
 */
void comm_stop(void)
{
    if (g_stop_event_fd != -1)
    {
        uint64_t val = 1;

        write(g_stop_event_fd, &val, sizeof(val));
    }
    g_running = false;
}
