// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/android/callback_android.h"
#include "base/android/jni_string.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/no_destructor.h"

// Must come after all headers that specialize FromJniType() / ToJniType().
#include "base/base_junit_tests_jni/JniCallbacksTest_jni.h"

namespace base::android {

namespace {
int g_run_count = 0;
bool g_once_callback_result = false;
bool g_once_callback2_result1 = false;
int g_once_callback2_result2 = 0;

std::string& GetOnceCallbackWithSubtypeResult() {
  static base::NoDestructor<std::string> instance;
  return *instance;
}
}  // namespace

static void JNI_JniCallbacksTest_TriggerOnceClosure(JNIEnv* env) {
  base::OnceClosure closure = base::BindOnce([]() { g_run_count++; });
  Java_JniCallbacksTest_callOnceClosure(env, std::move(closure));
}

static void JNI_JniCallbacksTest_TriggerOnceCallback(JNIEnv* env) {
  base::OnceCallback<void(int32_t)> callback =
      base::BindOnce([](int32_t r) { g_once_callback2_result2 = r; });
  Java_JniCallbacksTest_callOnceCallback(env, std::move(callback));
}

static void JNI_JniCallbacksTest_TriggerOnceCallback2(JNIEnv* env) {
  base::OnceCallback<void(bool, int32_t)> callback =
      base::BindOnce([](bool r1, int32_t r2) {
        g_once_callback2_result1 = r1;
        g_once_callback2_result2 = r2;
      });
  Java_JniCallbacksTest_callOnceCallback2(env, std::move(callback));
}

static void JNI_JniCallbacksTest_TriggerRepeatingClosure(JNIEnv* env) {
  base::RepeatingClosure closure = base::BindRepeating([]() { g_run_count++; });
  Java_JniCallbacksTest_callRepeatingClosure(env, closure);
}

static void JNI_JniCallbacksTest_TriggerRepeatingClosureMoveOnly(JNIEnv* env) {
  base::RepeatingClosure closure = base::BindRepeating([]() { g_run_count++; });
  Java_JniCallbacksTest_callRepeatingClosure(env, std::move(closure));
}

static void JNI_JniCallbacksTest_TriggerRepeatingCallback(JNIEnv* env) {
  // Test using std::move() with a const& param.
  base::RepeatingCallback<void(int32_t)> callback =
      base::BindRepeating([](int32_t r) { g_run_count++; });
  Java_JniCallbacksTest_callRepeatingCallback(env, std::move(callback));
}

static void JNI_JniCallbacksTest_TriggerRepeatingCallback2(JNIEnv* env) {
  base::RepeatingCallback<void(bool, int32_t)> callback =
      base::BindRepeating([](bool r1, int32_t r2) { g_run_count++; });
  Java_JniCallbacksTest_callRepeatingCallback2(env, callback);
}

static void JNI_JniCallbacksTest_ResetCounters(JNIEnv* env) {
  g_run_count = 0;
  g_once_callback_result = false;
  g_once_callback2_result1 = false;
  g_once_callback2_result2 = 0;
  GetOnceCallbackWithSubtypeResult().clear();
}

static base::OnceClosure JNI_JniCallbacksTest_GetOnceClosure(JNIEnv* env) {
  return base::BindOnce([]() { g_run_count++; });
}

static jint JNI_JniCallbacksTest_GetRunCount(JNIEnv* env) {
  return g_run_count;
}

static base::OnceCallback<void(bool)> JNI_JniCallbacksTest_GetOnceCallback(
    JNIEnv* env) {
  return base::BindOnce([](bool r) { g_once_callback_result = r; });
}

static jboolean JNI_JniCallbacksTest_GetOnceCallbackResult(JNIEnv* env) {
  return g_once_callback_result;
}

static base::RepeatingClosure JNI_JniCallbacksTest_GetRepeatingClosure(
    JNIEnv* env) {
  return base::BindRepeating([]() { g_run_count++; });
}

static base::RepeatingCallback<void(bool)>
JNI_JniCallbacksTest_GetRepeatingCallback(JNIEnv* env) {
  return base::BindRepeating([](bool r) { g_run_count++; });
}

static base::OnceCallback<void(bool, const jni_zero::JavaRef<jobject>&)>
JNI_JniCallbacksTest_GetOnceCallback2(JNIEnv* env) {
  return base::BindOnce([](bool r1, const jni_zero::JavaRef<jobject>& r2) {
    g_once_callback2_result1 = r1;
    g_once_callback2_result2 =
        jni_zero::FromJniType<int32_t>(jni_zero::AttachCurrentThread(), r2);
  });
}

static jboolean JNI_JniCallbacksTest_GetOnceCallback2Result1(JNIEnv* env) {
  return g_once_callback2_result1;
}

static jint JNI_JniCallbacksTest_GetOnceCallback2Result2(JNIEnv* env) {
  return g_once_callback2_result2;
}

static base::RepeatingCallback<void(bool, int32_t)>
JNI_JniCallbacksTest_GetRepeatingCallback2(JNIEnv* env) {
  return base::BindRepeating([](bool r1, int32_t r2) { g_run_count++; });
}

static base::OnceCallback<void(const jni_zero::JavaRef<jstring>&)>
JNI_JniCallbacksTest_GetOnceCallbackWithSubtype(JNIEnv* env) {
  return base::BindOnce([](const jni_zero::JavaRef<jstring>& r) {
    GetOnceCallbackWithSubtypeResult() =
        ConvertJavaStringToUTF8(jni_zero::AttachCurrentThread(), r);
  });
}

static ScopedJavaLocalRef<jstring>
JNI_JniCallbacksTest_GetOnceCallbackWithSubtypeResult(JNIEnv* env) {
  return ConvertUTF8ToJavaString(env, GetOnceCallbackWithSubtypeResult());
}

static base::RepeatingCallback<void(const jni_zero::JavaRef<jstring>&)>
JNI_JniCallbacksTest_GetRepeatingCallbackWithSubtype(JNIEnv* env) {
  return base::BindRepeating(
      [](const jni_zero::JavaRef<jstring>& r) { g_run_count++; });
}

static void JNI_JniCallbacksTest_PassOnceClosure(JNIEnv* env,
                                                 base::OnceClosure closure) {
  std::move(closure).Run();
}

static void JNI_JniCallbacksTest_PassOnceCallback(
    JNIEnv* env,
    base::OnceCallback<void(int32_t)> callback) {
  std::move(callback).Run(42);
}

static void JNI_JniCallbacksTest_PassRepeatingClosure(
    JNIEnv* env,
    base::RepeatingClosure closure) {
  closure.Run();
  closure.Run();
}

static void JNI_JniCallbacksTest_PassRepeatingCallback(
    JNIEnv* env,
    base::RepeatingCallback<void(int32_t)> callback) {
  callback.Run(1);
  callback.Run(2);
}

static void JNI_JniCallbacksTest_PassOnceCallback2(
    JNIEnv* env,
    base::OnceCallback<void(bool, int32_t)> callback) {
  std::move(callback).Run(true, 100);
}

static void JNI_JniCallbacksTest_PassRepeatingCallback2(
    JNIEnv* env,
    base::RepeatingCallback<void(bool, int32_t)> callback) {
  callback.Run(true, 1);
  callback.Run(false, 2);
}

static void JNI_JniCallbacksTest_PassOnceCallbackWithSubtype(
    JNIEnv* env,
    base::OnceCallback<void(const jni_zero::JavaRef<jstring>&)> callback) {
  std::move(callback).Run(jni_zero::NewAsciiString(env, "test string"));
}

static void JNI_JniCallbacksTest_PassOnceCallbackWithScopedSubtype(
    JNIEnv* env,
    base::OnceCallback<void(jni_zero::ScopedJavaLocalRef<jstring>)> callback) {
  std::move(callback).Run(jni_zero::NewAsciiString(env, "scoped string"));
}

static void JNI_JniCallbacksTest_PassRepeatingCallbackWithSubtype(
    JNIEnv* env,
    base::RepeatingCallback<void(const jni_zero::JavaRef<jstring>&)> callback) {
  callback.Run(jni_zero::NewAsciiString(env, "s1"));
  callback.Run(jni_zero::NewAsciiString(env, "s2"));
}

}  // namespace base::android

DEFINE_JNI(JniCallbacksTest)
