/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//#define LOG_NDEBUG 0
#define LOG_TAG "NativeThermalTest"

#include <condition_variable>
#include <jni.h>
#include <mutex>
#include <optional>
#include <thread>
#include <inttypes.h>
#include <time.h>
#include <unistd.h>
#include <math.h>
#include <vector>

#include <android/thermal.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/thread_annotations.h>
#include <log/log.h>
#include <sys/stat.h>
#include <utils/Errors.h>

using namespace android;
using namespace std::chrono_literals;
using android::base::StringPrintf;

struct AThermalTestContext {
    AThermalManager *mThermalMgr;
    std::mutex mMutex;
    std::condition_variable mCv;
    std::vector<AThermalStatus> mListenerStatus GUARDED_BY(mMutex);
};

static jclass    gNativeThermalTest_class;
static jmethodID gNativeThermalTest_thermalOverrideMethodID;

void onStatusChange(void *data, AThermalStatus status) {
    AThermalTestContext *ctx = static_cast<AThermalTestContext *>(data);
    if (ctx == nullptr) {
        return;
    } else {
        std::lock_guard<std::mutex> guard(ctx->mMutex);
        ctx->mListenerStatus.push_back(status);
        ctx->mCv.notify_all();
    }
}

static inline void setThermalStatusOverride(JNIEnv* env, jobject obj, int32_t level) {
    env->CallVoidMethod(obj, gNativeThermalTest_thermalOverrideMethodID, level);
}

static inline jstring returnJString(JNIEnv *env, std::optional<std::string> result) {
    if (result.has_value()) {
        return env->NewStringUTF(result.value().c_str());
    } else {
        return env->NewStringUTF("");
    }
}

static std::optional<std::string> testGetCurrentThermalStatus(
                                        JNIEnv *env, jobject obj, int32_t level) {
    AThermalTestContext ctx;
    std::unique_lock<std::mutex> lock(ctx.mMutex);

    ctx.mThermalMgr = AThermal_acquireManager();
    if (ctx.mThermalMgr == nullptr) {
        return "AThermal_acquireManager failed";
    }

    setThermalStatusOverride(env, obj, level);
    AThermalStatus thermalStatus = AThermal_getCurrentThermalStatus(ctx.mThermalMgr);
    if (thermalStatus == ATHERMAL_STATUS_ERROR) {
        return "getCurrentThermalStatus returns ATHERMAL_STATUS_ERROR";
    }
    // Verify the current thermal status is same as override
    if (thermalStatus != static_cast<AThermalStatus>(level)) {
        return StringPrintf("getCurrentThermalStatus %" PRId32 " != override %" PRId32 ".",
                            thermalStatus, level);
    }

    AThermal_releaseManager(ctx.mThermalMgr);
    return std::nullopt;
}

static jstring nativeTestGetCurrentThermalStatus(JNIEnv *env, jobject obj, jint level) {
    return returnJString(env, testGetCurrentThermalStatus(env, obj, static_cast<int32_t>(level)));
}

static std::optional<std::string> testRegisterThermalStatusListener(JNIEnv *env, jobject obj) {
    AThermalTestContext ctx;
    std::unique_lock<std::mutex> lock(ctx.mMutex);

    ctx.mThermalMgr = AThermal_acquireManager();
    if (ctx.mThermalMgr == nullptr) {
        return "AThermal_acquireManager failed";
    }

    // Register a listener with valid callback
    int ret = AThermal_registerThermalStatusListener(ctx.mThermalMgr, onStatusChange, &ctx);
    if (ret != 0) {
        return StringPrintf("AThermal_registerThermalStatusListener failed: %s",
                    strerror(ret));
    }

    // Expect the callback after registration
    if (ctx.mCv.wait_for(lock, 1s) == std::cv_status::timeout) {
        return "Listener callback should be called after registration";
    }

    // Verify the current thermal status is same as listener callback
    auto thermalStatus = AThermal_getCurrentThermalStatus(ctx.mThermalMgr);
    auto listenerStatus = ctx.mListenerStatus.back();
    if (thermalStatus != listenerStatus) {
        return StringPrintf("thermalStatus %" PRId32 " != Listener status %" PRId32 ".",
                            thermalStatus, listenerStatus);
    }

    // Change override level and verify the listener callback
    for (int32_t level = ATHERMAL_STATUS_NONE; level <= ATHERMAL_STATUS_SHUTDOWN; level++) {
        if (thermalStatus == level) {
            // skip overriding a status that is the current status which won't trigger callback
            continue;
        }
        setThermalStatusOverride(env, obj, level);
        if (ctx.mCv.wait_for(lock, 1s) == std::cv_status::timeout) {
            return StringPrintf("Listener callback timeout at level %" PRId32, level);
        }
        auto overrideStatus = static_cast<AThermalStatus>(level);
        auto listenerStatus = ctx.mListenerStatus.back();
        if (listenerStatus != overrideStatus) {
            return StringPrintf("Listener thermalStatus%" PRId32 " != override %" PRId32 ".",
                            listenerStatus, overrideStatus);
        }
    }

    // Unregister listener
    ret = AThermal_unregisterThermalStatusListener(ctx.mThermalMgr, onStatusChange, &ctx);
    if (ret != 0) {
        return StringPrintf("AThermal_unregisterThermalStatusListener failed: %s",
                    strerror(ret));
    }

    AThermal_releaseManager(ctx.mThermalMgr);
    return std::nullopt;
}

static jstring nativeTestRegisterThermalStatusListener(JNIEnv *env, jobject obj) {
    return returnJString(env, testRegisterThermalStatusListener(env, obj));
}

static std::optional<std::string> testThermalStatusRegisterNullListener() {
    AThermalTestContext ctx;
    std::unique_lock<std::mutex> lock(ctx.mMutex);
    ctx.mThermalMgr = AThermal_acquireManager();
    if (ctx.mThermalMgr == nullptr) {
        return StringPrintf("AThermal_acquireManager failed");
    }

    // Register a listener with null callback
    int ret = AThermal_registerThermalStatusListener(ctx.mThermalMgr, nullptr, &ctx);
    if (ret != EINVAL) {
        return "AThermal_registerThermalStatusListener should fail with null callback";
    }

    // Register a listener with null data
    ret = AThermal_registerThermalStatusListener(ctx.mThermalMgr, onStatusChange,
                                                 nullptr);
    if (ret != 0) {
        return StringPrintf("AThermal_registerThermalStatusListener with null data failed: %s",
                    strerror(ret));
    }

    // Unregister listener
    ret = AThermal_unregisterThermalStatusListener(ctx.mThermalMgr, onStatusChange,
                                                   nullptr);
    if (ret != 0) {
        return StringPrintf("AThermal_unregisterThermalStatusListener with null data failed: %s",
                    strerror(ret));
    }

    // Unregister listener with null callback and null data
    ret = AThermal_unregisterThermalStatusListener(ctx.mThermalMgr, nullptr, nullptr);
    if (ret != EINVAL) {
        return "AThermal_unregisterThermalStatusListener should fail with null listener";
    }

    AThermal_releaseManager(ctx.mThermalMgr);
    return std::nullopt;
}

static jstring nativeTestThermalStatusRegisterNullListener(JNIEnv *env, jobject) {
    return returnJString(env, testThermalStatusRegisterNullListener());
}

static std::optional<std::string> testThermalStatusListenerDoubleRegistration
                                                        (JNIEnv *env, jobject obj) {
    AThermalTestContext ctx;
    std::unique_lock<std::mutex> lock(ctx.mMutex);

    ctx.mThermalMgr = AThermal_acquireManager();
    if (ctx.mThermalMgr == nullptr) {
        return "AThermal_acquireManager failed";
    }

    // Register a listener with valid callback
    int ret = AThermal_registerThermalStatusListener(ctx.mThermalMgr, onStatusChange, &ctx);
    if (ret != 0) {
        return StringPrintf("AThermal_registerThermalStatusListener failed: %s",
                    strerror(ret));
    }

    // Expect listener callback for initial registration
    if (ctx.mCv.wait_for(lock, 1s) == std::cv_status::timeout) {
        return "Thermal listener callback timeout for initial registration";
    }

    // Register the listener again with same callback and data
    ret = AThermal_registerThermalStatusListener(ctx.mThermalMgr, onStatusChange, &ctx);
    if (ret != EINVAL) {
        return "Register should fail as listener already registered";
    }

    // Expect no listener callback for double registration
    if (ctx.mCv.wait_for(lock, 1s) != std::cv_status::timeout) {
        return "Thermal listener got callback after double registration.";
    }

    // Register a listener with same callback but null data
    ret = AThermal_registerThermalStatusListener(ctx.mThermalMgr, onStatusChange, nullptr);
    if (ret != 0) {
        return StringPrintf("Register listener with null data failed: %s", strerror(ret));
    }

    // Expect no listener callback for another registration
    if (ctx.mCv.wait_for(lock, 1s) != std::cv_status::timeout) {
        return "Thermal listener got callback after third registration.";
    }

    // Unregister listener
    ret = AThermal_unregisterThermalStatusListener(ctx.mThermalMgr, onStatusChange, &ctx);
    if (ret != 0) {
        return StringPrintf("AThermal_unregisterThermalStatusListener failed: %s",
                    strerror(ret));
    }

    setThermalStatusOverride(env, obj, ATHERMAL_STATUS_LIGHT);
    // Expect no listener callback
    if (ctx.mCv.wait_for(lock, 1s) != std::cv_status::timeout) {
        return "Thermal listener got callback after unregister.";
    }

    // Unregister listener already unregistered
    ret = AThermal_unregisterThermalStatusListener(ctx.mThermalMgr, onStatusChange, &ctx);
    if (ret != EINVAL) {
        return "Unregister should fail with listener already unregistered";
    }

    AThermal_releaseManager(ctx.mThermalMgr);
    return std::nullopt;
}

static jstring nativeTestThermalStatusListenerDoubleRegistration(JNIEnv *env, jobject obj) {
    return returnJString(env, testThermalStatusListenerDoubleRegistration(env, obj));
}

static std::optional<std::string> testGetThermalHeadroom(JNIEnv *, jobject) {
    AThermalTestContext ctx;
    std::unique_lock<std::mutex> lock(ctx.mMutex);

    ctx.mThermalMgr = AThermal_acquireManager();
    if (ctx.mThermalMgr == nullptr) {
        return "AThermal_acquireManager failed";
    }

    // Fairly light touch test only. More in-depth testing of the underlying
    // Thermal API functionality is done against the equivalent Java API.

    float headroom = AThermal_getThermalHeadroom(ctx.mThermalMgr, 0);
    if (isnan(headroom)) {
        // If the device doesn't support thermal headroom, return early.
        // This is not a failure.
        return std::nullopt;
    }

    if (headroom < 0.0f) {
        return StringPrintf("Expected non-negative headroom but got %2.2f",
                headroom);
    }
    if (headroom >= 10.0f) {
        return StringPrintf("Expected reasonably small (<10) headroom but got %2.2f", headroom);
    }

    AThermal_releaseManager(ctx.mThermalMgr);
    return std::nullopt;
}

static std::optional<std::string> testGetThermalHeadroomThresholds(JNIEnv *, jobject) {
    AThermalTestContext ctx;
    std::unique_lock<std::mutex> lock(ctx.mMutex);

    ctx.mThermalMgr = AThermal_acquireManager();
    if (ctx.mThermalMgr == nullptr) {
        return "AThermal_acquireManager failed";
    }

    const AThermalHeadroomThreshold *thresholds = nullptr;
    size_t size;
    auto ret = AThermal_getThermalHeadroomThresholds(ctx.mThermalMgr, &thresholds, &size);
    if (ret == ENOSYS) {
        // if feature is disabled
        return std::nullopt;
    }
    if (ret != OK) {
        return StringPrintf("Failed to get thermal headroom thresholds result");
    }
    if (thresholds == nullptr || size == 0) {
        // if device doesn't support the thermal headroom thresholds then skip
        return std::nullopt;
    }
    float lastHeadroom = thresholds[0].headroom;
    int lastStatus = thresholds[0].thermalStatus;
    for (int i = 0; i < size; i++) {
        auto headroom = thresholds[i].headroom;
        int status = thresholds[i].thermalStatus;
        if (!isnan(headroom)) {
            if (status == AThermalStatus::ATHERMAL_STATUS_SEVERE && headroom != 1.0f) {
                return StringPrintf("Expected threshold 1.0f for SEVERE status but got %2.2f",
                                    headroom);
            }
            if (headroom < lastHeadroom) {
                return StringPrintf("Thermal headroom threshold for status %d is %2.2f should not "
                                    "be smaller than a lower status %d which is %2.2f",
                                    status, headroom, lastStatus, lastHeadroom);
            }
            if (headroom < 0) {
                return StringPrintf("Expected non-negative headroom threshold but got %2.2f for "
                                    "status %d",
                                    headroom, status);
            }
        }
    }
    AThermal_releaseManager(ctx.mThermalMgr);
    return std::nullopt;
}

static jstring nativeTestGetThermalHeadroom(JNIEnv *env, jobject obj) {
    return returnJString(env, testGetThermalHeadroom(env, obj));
}

static jstring nativeTestGetThermalHeadroomThresholds(JNIEnv *env, jobject obj) {
  return returnJString(env, testGetThermalHeadroomThresholds(env, obj));
}

extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) {
    JNIEnv* env;
    const JNINativeMethod methodTable[] = {
        {"nativeTestGetCurrentThermalStatus", "(I)Ljava/lang/String;",
         (void*)nativeTestGetCurrentThermalStatus},
        {"nativeTestRegisterThermalStatusListener", "()Ljava/lang/String;",
         (void*)nativeTestRegisterThermalStatusListener},
        {"nativeTestThermalStatusRegisterNullListener", "()Ljava/lang/String;",
         (void*)nativeTestThermalStatusRegisterNullListener},
        {"nativeTestThermalStatusListenerDoubleRegistration", "()Ljava/lang/String;",
         (void*)nativeTestThermalStatusListenerDoubleRegistration},
        {"nativeTestGetThermalHeadroom", "()Ljava/lang/String;",
         (void*)nativeTestGetThermalHeadroom},
        {"nativeTestGetThermalHeadroomThresholds", "()Ljava/lang/String;",
         (void*)nativeTestGetThermalHeadroomThresholds},
    };
    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
        return JNI_ERR;
    }
    gNativeThermalTest_class = env->FindClass("android/thermal/cts/NativeThermalTest");
    gNativeThermalTest_thermalOverrideMethodID =
                env->GetMethodID(gNativeThermalTest_class, "setOverrideStatus", "(I)V");
    if (gNativeThermalTest_thermalOverrideMethodID == nullptr) {
        return JNI_ERR;
    }
    if (env->RegisterNatives(gNativeThermalTest_class, methodTable,
            sizeof(methodTable) / sizeof(JNINativeMethod)) != JNI_OK) {
        return JNI_ERR;
    }
    return JNI_VERSION_1_6;
}
