#include <iostream>
#include <cerrno>
#include <cstdint>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
#include <sys/timerfd.h>
#include <linux/input.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <signal.h>
#include <mutex>
#include <thread>
#include <atomic>

namespace {
constexpr uint16_t kPort = 8888;
const char* const kDefaultEvdev = "/dev/input/event0";

// 心跳间隔须小于服务端 SO_RCVTIMEO（200ms）；留 4× 余量
constexpr int kHeartbeatIntervalMs = 50;

// 用 atomic 以便在信号处理与发送线程之间安全共享
std::atomic<bool> g_quit{false};

void onSignal(int /*sig*/) {
    g_quit.store(true, std::memory_order_relaxed);
}

void usage(const char* prog) {
    std::cerr << "用法: " << prog << " [服务器IP] [evdev设备]\n"
              << "默认: 127.0.0.1:" << kPort << "  " << kDefaultEvdev << "\n"
              << "W/S/↑/↓ 一路，A/D/←/→ 另一路；倒车时左右互换。松手 1/2，空格 t。\n"
              << "+ / - 调速(协议 + / -，共5档)。每 " << kHeartbeatIntervalMs
              << " ms 重发状态；服务端超时无包则回中。需 evdev 权限。\n";
}

bool connectServer(const char* host, int* out_fd) {
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd < 0) {
        perror("socket");
        return false;
    }
    sockaddr_in addr{};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(kPort);
    if (inet_pton(AF_INET, host, &addr.sin_addr) != 1) {
        std::cerr << "无效地址: " << host << std::endl;
        close(fd);
        return false;
    }
    if (connect(fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
        perror("connect");
        close(fd);
        return false;
    }
    int one = 1;
    setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
    *out_fd = fd;
    return true;
}

// 阻塞发送，确保所有字节到达内核缓冲区
bool sendAll(int sock, const void* data, size_t len) {
    const auto* p = static_cast<const unsigned char*>(data);
    size_t off = 0;
    while (off < len) {
        ssize_t n = send(sock, p + off, len - off, MSG_NOSIGNAL);
        if (n < 0) {
            if (errno == EINTR) continue;
            perror("send");
            return false;
        }
        if (n == 0) return false;
        off += static_cast<size_t>(n);
    }
    return true;
}

bool sendCmd(int sock, char cmd) { return sendAll(sock, &cmd, 1); }

// ---- 按键状态 -------------------------------------------------------

enum class AxisSlot { None, Fwd, Back, Left, Right };

constexpr char kCmdNeutralPwm5 = '1';
constexpr char kCmdNeutralPwm6 = '2';
constexpr char kCmdFullStop    = 't';
constexpr char kCmdSpeedUp     = '+';
constexpr char kCmdSpeedDown   = '-';

bool isSpeedKey(unsigned short code) {
    return code == KEY_MINUS || code == KEY_KPMINUS ||
           code == KEY_KPPLUS || code == KEY_EQUAL;
}

AxisSlot keyCodeToSlot(unsigned short code) {
    switch (code) {
        case KEY_W: case KEY_UP:    return AxisSlot::Fwd;
        case KEY_S: case KEY_DOWN:  return AxisSlot::Back;
        case KEY_A: case KEY_LEFT:  return AxisSlot::Left;
        case KEY_D: case KEY_RIGHT: return AxisSlot::Right;
        default:                    return AxisSlot::None;
    }
}

bool isTrackedKey(unsigned short code) {
    return keyCodeToSlot(code) != AxisSlot::None;
}

struct ComboState {
    int n_fwd = 0, n_back = 0, n_left = 0, n_right = 0;
    char conflict5 = 'w', conflict6 = 'a';

    void onPress(AxisSlot slot) {
        switch (slot) {
            case AxisSlot::Fwd:   ++n_fwd;   if (n_back  > 0) conflict5 = 'w'; break;
            case AxisSlot::Back:  ++n_back;  if (n_fwd   > 0) conflict5 = 's'; break;
            case AxisSlot::Left:  ++n_left;  if (n_right > 0) conflict6 = 'a'; break;
            case AxisSlot::Right: ++n_right; if (n_left  > 0) conflict6 = 'd'; break;
            default: break;
        }
    }
    void onRelease(AxisSlot slot) {
        switch (slot) {
            case AxisSlot::Fwd:   if (n_fwd   > 0) --n_fwd;   break;
            case AxisSlot::Back:  if (n_back  > 0) --n_back;  break;
            case AxisSlot::Left:  if (n_left  > 0) --n_left;  break;
            case AxisSlot::Right: if (n_right > 0) --n_right; break;
            default: break;
        }
    }
    char desiredPwm5() const {
        if (n_fwd == 0 && n_back == 0) return kCmdNeutralPwm5;
        if (n_fwd > 0 && n_back == 0)  return 'w';
        if (n_back > 0 && n_fwd == 0)  return 's';
        return conflict5;
    }
    bool reversing() const { return desiredPwm5() == 's'; }
    char desiredPwm6() const {
        char raw;
        if      (n_left == 0 && n_right == 0) raw = kCmdNeutralPwm6;
        else if (n_left > 0 && n_right == 0)  raw = 'a';
        else if (n_right > 0 && n_left == 0)  raw = 'd';
        else                                   raw = conflict6;
        if (!reversing()) return raw;
        if (raw == 'a') return 'd';
        if (raw == 'd') return 'a';
        return raw;
    }
};

// ---- 主线程 / 发送线程共享的状态 ------------------------------------

struct SharedState {
    std::mutex mu;
    ComboState combo;
    // 一次性命令（'t' / '+' / '-'）；发送线程取走后清零
    char pending_cmd = 0;
};

// ---- 发送线程：独立节拍，与 evdev 事件完全解耦 ----------------------
// sock 只在本线程使用，无需加锁
// timerfd 由内核用 CLOCK_MONOTONIC 驱动，不受 NTP/时钟调整影响，比 nanosleep 更稳定
void runSenderThread(int sock, SharedState* shared) {
    const int tfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
    if (tfd < 0) {
        perror("[sender] timerfd_create");
        g_quit.store(true);
        return;
    }
    {
        const long ns = static_cast<long>(kHeartbeatIntervalMs) * 1000000L;
        struct itimerspec its{};
        its.it_value.tv_nsec    = ns;
        its.it_interval.tv_nsec = ns;
        if (timerfd_settime(tfd, 0, &its, nullptr) < 0) {
            perror("[sender] timerfd_settime");
            close(tfd);
            g_quit.store(true);
            return;
        }
    }

    std::cerr << "[sender] 启动，timerfd 心跳 " << kHeartbeatIntervalMs << " ms\n";
    uint64_t send_count = 0;

    while (!g_quit.load(std::memory_order_relaxed)) {
        // 阻塞等待下一个 timer tick；read 返回 exp = 已过期次数（落后时 > 1）
        uint64_t exp = 0;
        ssize_t r = read(tfd, &exp, sizeof(exp));
        if (r < 0) {
            if (errno == EINTR) continue;
            perror("[sender] read timerfd");
            break;
        }
        if (r != static_cast<ssize_t>(sizeof(exp))) {
            break;
        }
        if (exp > 1) {
            std::cerr << "[sender] 警告：落后 " << exp << " 个心跳节拍，仅发一帧最新状态\n";
        }

        char pending = 0;
        char d5, d6;
        {
            std::lock_guard<std::mutex> lk(shared->mu);
            d5 = shared->combo.desiredPwm5();
            d6 = shared->combo.desiredPwm6();
            pending = shared->pending_cmd;
            shared->pending_cmd = 0;
        }

        bool ok = true;
        if (pending != 0) {
            ok = sendCmd(sock, pending);
        }
        if (ok) {
            char buf[2] = {d5, d6};
            ok = sendAll(sock, buf, sizeof(buf));
        }
        if (!ok) {
            std::cerr << "[sender] send 失败，退出\n";
            g_quit.store(true);
            break;
        }

        ++send_count;
        if (send_count % 20 == 0) {  // 每 ~1s 打一次诊断
            std::cerr << "[sender] 已发 " << send_count << " 帧，当前状态: "
                      << d5 << '/' << d6 << '\n';
        }
    }

    close(tfd);
    std::cerr << "[sender] 退出，共发 " << send_count << " 帧\n";
}

// ---- 主线程：只读 evdev，更新 SharedState，不直接发送 ---------------
void handleKeyEvent(const input_event& ev, SharedState* shared) {
    if (ev.type != EV_KEY) return;
    if (ev.value == 2) return;  // 长按 repeat：状态不变，发送线程会持续发当前状态

    std::lock_guard<std::mutex> lk(shared->mu);

    if (ev.code == KEY_SPACE) {
        if (ev.value == 1) shared->pending_cmd = kCmdFullStop;
        return;
    }
    if (isSpeedKey(ev.code)) {
        if (ev.value != 1) return;
        shared->pending_cmd = (ev.code == KEY_MINUS || ev.code == KEY_KPMINUS)
            ? kCmdSpeedDown : kCmdSpeedUp;
        return;
    }
    if (!isTrackedKey(ev.code)) return;
    const AxisSlot slot = keyCodeToSlot(ev.code);
    if (slot == AxisSlot::None) return;
    if (ev.value == 1) shared->combo.onPress(slot);
    else if (ev.value == 0) shared->combo.onRelease(slot);
}

}  // namespace

int main(int argc, char** argv) {
    const char* host = "127.0.0.1";
    const char* evdev_path = kDefaultEvdev;

    if (argc > 3) { usage(argv[0]); return 1; }
    if (argc >= 2) host = argv[1];
    if (argc == 3) evdev_path = argv[2];

    int sock = -1;
    if (!connectServer(host, &sock)) return 1;

    int evfd = open(evdev_path, O_RDONLY);
    if (evfd < 0) {
        perror("open evdev");
        std::cerr << "无法打开 " << evdev_path << std::endl;
        close(sock);
        return 1;
    }

    signal(SIGINT,  onSignal);
    signal(SIGTERM, onSignal);

    std::cout << "已连接 " << host << ":" << kPort << "\n"
              << "设备 " << evdev_path << " — 心跳 " << kHeartbeatIntervalMs
              << " ms；+/- 调速；倒车 A/D 对调；松手 1/2；空格 t\n";

    SharedState shared;

    // sock 由发送线程独占；主线程结束后先 join 再 close(sock)
    std::thread sender(runSenderThread, sock, &shared);

    input_event ev{};
    while (!g_quit.load(std::memory_order_relaxed)) {
        // poll 加超时：即使 evdev 长时间无事件也能定期检查 g_quit
        struct pollfd pfd{evfd, POLLIN, 0};
        const int r = poll(&pfd, 1, 500);
        if (r < 0) {
            if (errno == EINTR) continue;
            perror("poll evdev");
            g_quit.store(true);
            break;
        }
        if (r == 0) continue;
        if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
            std::cerr << "evdev 设备异常\n";
            g_quit.store(true);
            break;
        }
        if (pfd.revents & POLLIN) {
            ssize_t n = read(evfd, &ev, sizeof(ev));
            if (n < 0) {
                if (errno == EINTR) continue;
                perror("read evdev");
                g_quit.store(true);
                break;
            }
            if (n == static_cast<ssize_t>(sizeof(ev))) {
                handleKeyEvent(ev, &shared);
            }
        }
    }

    g_quit.store(true);
    sender.join();   // 等发送线程退出后再关闭 sock
    close(evfd);
    close(sock);
    return 0;
}
