#include "libretro_frontend.h"

#include <jni.h>
#include <android/log.h>
#include <android/native_window_jni.h>

#define LOG_TAG "JniBridge"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

extern "C" {

JNIEXPORT jboolean JNICALL
Java_com_lazy_emulate_emulation_NativeLibretro_nativeLoadCore(JNIEnv* env, jobject, jstring corePath) {
    const char* path = env->GetStringUTFChars(corePath, nullptr);
    bool result = LibretroFrontend::instance().loadCore(path);
    env->ReleaseStringUTFChars(corePath, path);
    return result;
}

JNIEXPORT jboolean JNICALL
Java_com_lazy_emulate_emulation_NativeLibretro_nativeLoadGame(JNIEnv* env, jobject, jstring romPath) {
    const char* path = env->GetStringUTFChars(romPath, nullptr);
    bool result = LibretroFrontend::instance().loadGame(path);
    env->ReleaseStringUTFChars(romPath, path);
    return result;
}

JNIEXPORT void JNICALL
Java_com_lazy_emulate_emulation_NativeLibretro_nativeStart(JNIEnv*, jobject) {
    LibretroFrontend::instance().start();
}

JNIEXPORT void JNICALL
Java_com_lazy_emulate_emulation_NativeLibretro_nativePause(JNIEnv*, jobject) {
    LibretroFrontend::instance().pause();
}

JNIEXPORT void JNICALL
Java_com_lazy_emulate_emulation_NativeLibretro_nativeResume(JNIEnv*, jobject) {
    LibretroFrontend::instance().resume();
}

JNIEXPORT void JNICALL
Java_com_lazy_emulate_emulation_NativeLibretro_nativeStop(JNIEnv*, jobject) {
    LibretroFrontend::instance().stop();
}

JNIEXPORT void JNICALL
Java_com_lazy_emulate_emulation_NativeLibretro_nativeReset(JNIEnv*, jobject) {
    LibretroFrontend::instance().reset();
}

JNIEXPORT void JNICALL
Java_com_lazy_emulate_emulation_NativeLibretro_nativeSetSurface(JNIEnv* env, jobject, jobject surface) {
    if (surface) {
        ANativeWindow* window = ANativeWindow_fromSurface(env, surface);
        LibretroFrontend::instance().setWindow(window);
        ANativeWindow_release(window); // setWindow does its own acquire
    } else {
        LibretroFrontend::instance().releaseWindow();
    }
}

JNIEXPORT void JNICALL
Java_com_lazy_emulate_emulation_NativeLibretro_nativeReleaseSurface(JNIEnv*, jobject) {
    LibretroFrontend::instance().releaseWindow();
}

JNIEXPORT void JNICALL
Java_com_lazy_emulate_emulation_NativeLibretro_nativeSetButtonState(JNIEnv*, jobject, jint state) {
    LibretroFrontend::instance().setButtonState(static_cast<uint16_t>(state));
}

JNIEXPORT void JNICALL
Java_com_lazy_emulate_emulation_NativeLibretro_nativeSetAnalogState(JNIEnv*, jobject, jint stick, jshort x, jshort y) {
    LibretroFrontend::instance().setAnalogState(stick, x, y);
}

JNIEXPORT jboolean JNICALL
Java_com_lazy_emulate_emulation_NativeLibretro_nativeSaveState(JNIEnv* env, jobject, jstring path) {
    const char* p = env->GetStringUTFChars(path, nullptr);
    bool result = LibretroFrontend::instance().saveState(p);
    env->ReleaseStringUTFChars(path, p);
    return result;
}

JNIEXPORT jboolean JNICALL
Java_com_lazy_emulate_emulation_NativeLibretro_nativeLoadState(JNIEnv* env, jobject, jstring path) {
    const char* p = env->GetStringUTFChars(path, nullptr);
    bool result = LibretroFrontend::instance().loadState(p);
    env->ReleaseStringUTFChars(path, p);
    return result;
}

JNIEXPORT void JNICALL
Java_com_lazy_emulate_emulation_NativeLibretro_nativeSetAudioEnabled(JNIEnv*, jobject, jboolean enabled) {
    LibretroFrontend::instance().setAudioEnabled(enabled);
}

JNIEXPORT void JNICALL
Java_com_lazy_emulate_emulation_NativeLibretro_nativeSetFrameSkip(JNIEnv*, jobject, jint skip) {
    LibretroFrontend::instance().setFrameSkip(skip);
}

JNIEXPORT void JNICALL
Java_com_lazy_emulate_emulation_NativeLibretro_nativeSetDisplayMode(JNIEnv*, jobject, jint mode) {
    LibretroFrontend::instance().setDisplayMode(mode);
}

JNIEXPORT void JNICALL
Java_com_lazy_emulate_emulation_NativeLibretro_nativeSetSystemDir(JNIEnv* env, jobject, jstring dir) {
    const char* d = env->GetStringUTFChars(dir, nullptr);
    LibretroFrontend::instance().setSystemDir(d);
    env->ReleaseStringUTFChars(dir, d);
}

JNIEXPORT void JNICALL
Java_com_lazy_emulate_emulation_NativeLibretro_nativeSetSaveDir(JNIEnv* env, jobject, jstring dir) {
    const char* d = env->GetStringUTFChars(dir, nullptr);
    LibretroFrontend::instance().setSaveDir(d);
    env->ReleaseStringUTFChars(dir, d);
}

JNIEXPORT void JNICALL
Java_com_lazy_emulate_emulation_NativeLibretro_nativeSetControllerPortDevice(JNIEnv*, jobject, jint port, jint device) {
    LibretroFrontend::instance().setControllerPortDevice(static_cast<unsigned>(port), static_cast<unsigned>(device));
}

JNIEXPORT void JNICALL
Java_com_lazy_emulate_emulation_NativeLibretro_nativeSetPendingControllerDevice(JNIEnv*, jobject, jint device) {
    LibretroFrontend::instance().setPendingControllerDevice(device);
}

JNIEXPORT void JNICALL
Java_com_lazy_emulate_emulation_NativeLibretro_nativeSetCoreOption(JNIEnv* env, jobject, jstring key, jstring value) {
    const char* k = env->GetStringUTFChars(key, nullptr);
    const char* v = env->GetStringUTFChars(value, nullptr);
    LibretroFrontend::instance().setCoreOption(k, v);
    env->ReleaseStringUTFChars(value, v);
    env->ReleaseStringUTFChars(key, k);
}

} // extern "C"
