/**
 * JNI bridge between Kotlin/Java and libquicproquo_ffi.
 *
 * Compile with:
 *   gcc -shared -fPIC -o libquicproquo_jni.so \
 *       -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/linux" \
 *       dev_quicproquo_NativeBridge.c \
 *       -L ../../../../target/release -lquicproquo_ffi
 */

#include <jni.h>
#include <stdint.h>
#include <string.h>

/* Forward declarations for libquicproquo_ffi functions. */
typedef struct QpqHandle QpqHandle;

extern QpqHandle* qpq_connect(const char* server, const char* ca_cert, const char* server_name);
extern int qpq_login(QpqHandle* handle, const char* username, const char* password);
extern int qpq_send(QpqHandle* handle, const char* recipient,
                     const uint8_t* message, size_t message_len);
extern int qpq_receive(QpqHandle* handle, uint32_t timeout_ms, char** out_json);
extern void qpq_disconnect(QpqHandle* handle);
extern const char* qpq_last_error(const QpqHandle* handle);
extern void qpq_free_string(char* ptr);

/* --- JNI exports --- */

JNIEXPORT jlong JNICALL
Java_dev_quicproquo_NativeBridge_nativeConnect(
    JNIEnv* env, jclass cls,
    jstring server, jstring caCert, jstring serverName)
{
    const char* s = (*env)->GetStringUTFChars(env, server, NULL);
    const char* c = (*env)->GetStringUTFChars(env, caCert, NULL);
    const char* n = (*env)->GetStringUTFChars(env, serverName, NULL);

    QpqHandle* h = qpq_connect(s, c, n);

    (*env)->ReleaseStringUTFChars(env, server, s);
    (*env)->ReleaseStringUTFChars(env, caCert, c);
    (*env)->ReleaseStringUTFChars(env, serverName, n);

    return (jlong)(uintptr_t)h;
}

JNIEXPORT jint JNICALL
Java_dev_quicproquo_NativeBridge_nativeLogin(
    JNIEnv* env, jclass cls,
    jlong handle, jstring username, jstring password)
{
    QpqHandle* h = (QpqHandle*)(uintptr_t)handle;
    const char* u = (*env)->GetStringUTFChars(env, username, NULL);
    const char* p = (*env)->GetStringUTFChars(env, password, NULL);

    int code = qpq_login(h, u, p);

    (*env)->ReleaseStringUTFChars(env, username, u);
    (*env)->ReleaseStringUTFChars(env, password, p);
    return code;
}

JNIEXPORT jint JNICALL
Java_dev_quicproquo_NativeBridge_nativeSend(
    JNIEnv* env, jclass cls,
    jlong handle, jstring recipient, jbyteArray message)
{
    QpqHandle* h = (QpqHandle*)(uintptr_t)handle;
    const char* r = (*env)->GetStringUTFChars(env, recipient, NULL);
    jsize len = (*env)->GetArrayLength(env, message);
    jbyte* bytes = (*env)->GetByteArrayElements(env, message, NULL);

    int code = qpq_send(h, r, (const uint8_t*)bytes, (size_t)len);

    (*env)->ReleaseByteArrayElements(env, message, bytes, JNI_ABORT);
    (*env)->ReleaseStringUTFChars(env, recipient, r);
    return code;
}

JNIEXPORT jstring JNICALL
Java_dev_quicproquo_NativeBridge_nativeReceive(
    JNIEnv* env, jclass cls,
    jlong handle, jint timeoutMs)
{
    QpqHandle* h = (QpqHandle*)(uintptr_t)handle;
    char* json = NULL;
    int code = qpq_receive(h, (uint32_t)timeoutMs, &json);

    if (code != 0 || json == NULL) {
        if (json) qpq_free_string(json);
        return NULL;
    }

    jstring result = (*env)->NewStringUTF(env, json);
    qpq_free_string(json);
    return result;
}

JNIEXPORT void JNICALL
Java_dev_quicproquo_NativeBridge_nativeDisconnect(
    JNIEnv* env, jclass cls, jlong handle)
{
    QpqHandle* h = (QpqHandle*)(uintptr_t)handle;
    if (h) {
        qpq_disconnect(h);
    }
}

JNIEXPORT jstring JNICALL
Java_dev_quicproquo_NativeBridge_nativeLastError(
    JNIEnv* env, jclass cls, jlong handle)
{
    QpqHandle* h = (QpqHandle*)(uintptr_t)handle;
    const char* err = qpq_last_error(h);
    if (!err) return NULL;
    return (*env)->NewStringUTF(env, err);
}
