
#pragma once
#include <cstdio>
#include <cerrno>
#include <cstring>
#include <chrono>
#include <thread>

#ifndef NETPLUS_DEBUG
#define NETPLUS_DEBUG 0
#endif

#if NETPLUS_DEBUG

// optional: include time stamps
#ifndef NETPLUS_DEBUG_TS
#define NETPLUS_DEBUG_TS 1
#endif

static inline unsigned long long _ndbg_now_us() {
    using namespace std::chrono;
    return (unsigned long long)duration_cast<microseconds>(
        steady_clock::now().time_since_epoch()
    ).count();
}

static inline void _ndbg_print_prefix(int tid, int fd, const char* tag) {
#if NETPLUS_DEBUG_TS
    std::fprintf(stderr, "[%llu][T%02d][fd=%d][%s] ",
                 _ndbg_now_us(), tid, fd, tag);
#else
    std::fprintf(stderr, "[T%02d][fd=%d][%s] ", tid, fd, tag);
#endif
}

#define NDBG(tid, fd, tag, fmt, ...) \
    do { \
        _ndbg_print_prefix((tid), (fd), (tag)); \
        std::fprintf(stderr, fmt "\n", ##__VA_ARGS__); \
        std::fflush(stderr); \
    } while(0)

#define NDBG_ERR(tid, fd, tag, fmt, ...) \
    do { \
        int _e = errno; \
        _ndbg_print_prefix((tid), (fd), (tag)); \
        std::fprintf(stderr, fmt " (errno=%d:%s)\n", ##__VA_ARGS__, _e, std::strerror(_e)); \
        std::fflush(stderr); \
    } while(0)

#else

// compiled out
#define NDBG(tid, fd, tag, fmt, ...) do {} while(0)
#define NDBG_ERR(tid, fd, tag, fmt, ...) do {} while(0)

#endif
