/*
 * Thin JNI bridge over hev-socks5-tunnel. Kotlin owns lifecycle and threading;
 * this file only marshals arguments and forwards to the native engine.
 *
 * hev_socks5_tunnel_quit() spins forever waiting for event_fds when the engine
 * is not running (see hev_socks5_tunnel_stop), so stop must never be issued
 * unless a start is actually in flight. The `running` flag mirrors the
 * is_working guard from the reference hev-jni.c.
 */
#include <jni.h>
#include <string.h>
#include <stdatomic.h>
#include <android/log.h>

#include "hev-socks5-tunnel.h"

#define LOG_TAG "vojo-tun2socks"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

static atomic_int running = 0;

/* Blocks until nativeStop()/quit is called or the engine errors out. */
JNIEXPORT jint JNICALL
Java_chat_vojo_proxy_core_Tun2Socks_nativeStart(JNIEnv *env, jclass clazz,
                                                jstring config, jint tunFd)
{
    (void) clazz;

    int expected = 0;
    if (!atomic_compare_exchange_strong(&running, &expected, 1)) {
        LOGE("engine already running, refusing double start");
        return -2;
    }

    const char *cfg = (*env)->GetStringUTFChars(env, config, NULL);
    if (!cfg) {
        LOGE("failed to read config string");
        atomic_store(&running, 0);
        return -1;
    }
    unsigned int len = (unsigned int) strlen(cfg);
    LOGI("engine start: fd=%d config=%u bytes", tunFd, len);
    int ret = hev_socks5_tunnel_main_from_str((const unsigned char *) cfg, len, tunFd);
    (*env)->ReleaseStringUTFChars(env, config, cfg);
    LOGI("engine stopped: ret=%d", ret);
    atomic_store(&running, 0);
    return ret;
}

JNIEXPORT void JNICALL
Java_chat_vojo_proxy_core_Tun2Socks_nativeStop(JNIEnv *env, jclass clazz)
{
    (void) env; (void) clazz;
    if (atomic_load(&running)) {
        hev_socks5_tunnel_quit();
    } else {
        LOGI("engine not running, stop ignored");
    }
}

/* Returns [txPackets, txBytes, rxPackets, rxBytes]. */
JNIEXPORT jlongArray JNICALL
Java_chat_vojo_proxy_core_Tun2Socks_nativeStats(JNIEnv *env, jclass clazz)
{
    (void) clazz;
    size_t txp = 0, txb = 0, rxp = 0, rxb = 0;
    hev_socks5_tunnel_stats(&txp, &txb, &rxp, &rxb);

    jlong vals[4];
    vals[0] = (jlong) txp;
    vals[1] = (jlong) txb;
    vals[2] = (jlong) rxp;
    vals[3] = (jlong) rxb;

    jlongArray arr = (*env)->NewLongArray(env, 4);
    if (arr) {
        (*env)->SetLongArrayRegion(env, arr, 0, 4, vals);
    }
    return arr;
}
