/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * 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.
 */

#include "send_callback.h"

#include <uv.h>

#include "telephony_log_wrapper.h"

namespace OHOS {
namespace Telephony {
static const int32_t CALLBACK_VALUE_LEN = 2;

SendSmsResult SendCallback::WrapSmsSendResult(const ISendShortMessageCallback::SmsSendResult result)
{
    switch (result) {
        case ISendShortMessageCallback::SmsSendResult::SEND_SMS_SUCCESS: {
            return SendSmsResult::SEND_SMS_SUCCESS;
        }
        case ISendShortMessageCallback::SmsSendResult::SEND_SMS_FAILURE_RADIO_OFF: {
            return SendSmsResult::SEND_SMS_FAILURE_RADIO_OFF;
        }
        case ISendShortMessageCallback::SmsSendResult::SEND_SMS_FAILURE_SERVICE_UNAVAILABLE: {
            return SendSmsResult::SEND_SMS_FAILURE_SERVICE_UNAVAILABLE;
        }
        default: {
            return SendSmsResult::SEND_SMS_FAILURE_UNKNOWN;
        }
    }
}

SendCallback::SendCallback(bool hasCallback, napi_env env, napi_ref thisVarRef, napi_ref callbackRef)
    : hasCallback_(hasCallback), env_(env), thisVarRef_(thisVarRef), callbackRef_(callbackRef)
{
    if (hasCallback_) {
        napi_reference_ref(env_, thisVarRef_, nullptr);
        napi_reference_ref(env_, callbackRef_, nullptr);
    }
}

SendCallback::~SendCallback()
{
    if (hasCallback_) {
        uint32_t refCount = 0;
        if (napi_reference_unref(env_, thisVarRef_, &refCount) == napi_ok && refCount == 0) {
            napi_delete_reference(env_, thisVarRef_);
        }
        if (napi_reference_unref(env_, callbackRef_, &refCount) == napi_ok && refCount == 0) {
            napi_delete_reference(env_, callbackRef_);
        }
    }
    env_ = nullptr;
    thisVarRef_ = nullptr;
    callbackRef_ = nullptr;
}

void CompleteSmsSendWork(uv_work_t *work, int status)
{
    TELEPHONY_LOGI("CompleteSmsSendWork start");
    if (work == nullptr) {
        return;
    }
    if (work->data == nullptr) {
        delete work;
        return;
    }
    std::unique_ptr<SendCallbackContext> pContext(static_cast<SendCallbackContext *>(work->data));

    napi_env env = pContext->env;
    napi_ref thisVarRef = pContext->thisVarRef;
    napi_ref callbackRef = pContext->callbackRef;
    SendSmsResult wrapResult = pContext->result;
    napi_handle_scope scope = nullptr;
    if (napi_open_handle_scope(env, &scope) != napi_ok || scope == nullptr) {
        TELEPHONY_LOGE("CompleteSmsSendWork work is nullptr!");
        delete work;
        return;
    }
    napi_value callbackFunc = nullptr;
    if (napi_get_reference_value(env, callbackRef, &callbackFunc) != napi_ok || callbackFunc == nullptr) {
        napi_close_handle_scope(env, scope);
        delete work;
        return;
    }
    napi_value callbackValues[CALLBACK_VALUE_LEN] = { 0 };
    callbackValues[0] = NapiUtil::CreateUndefined(env);
    napi_create_object(env, &callbackValues[1]);
    napi_value sendResultValue = nullptr;
    napi_create_int32(env, wrapResult, &sendResultValue);
    napi_set_named_property(env, callbackValues[1], "result", sendResultValue);

    napi_value thisVar = nullptr;
    if (napi_get_reference_value(env, thisVarRef, &thisVar) != napi_ok || thisVar == nullptr) {
        napi_close_handle_scope(env, scope);
        delete work;
        return;
    }

    napi_value callbackResult = nullptr;
    napi_call_function(env, thisVar, callbackFunc, CALLBACK_VALUE_LEN, callbackValues, &callbackResult);
    napi_close_handle_scope(env, scope);
    delete work;
    TELEPHONY_LOGI("CompleteSmsSendWork end");
}

void SendCallback::OnSmsSendResult(const ISendShortMessageCallback::SmsSendResult result)
{
    TELEPHONY_LOGI("OnSmsSendResult start");
    if (!hasCallback_) {
        TELEPHONY_LOGE("OnSmsSendResult hasCallback_ is false");
        return;
    }
    uv_loop_s *loop = nullptr;
    napi_get_uv_event_loop(env_, &loop);
    SendCallbackContext *pContext = new SendCallbackContext;
    pContext->env = env_;
    pContext->thisVarRef = thisVarRef_;
    pContext->callbackRef = callbackRef_;
    pContext->result = WrapSmsSendResult(result);
    uv_work_t *work = new uv_work_t;
    work->data = static_cast<void *>(pContext);

    int32_t errCode = uv_queue_work_with_qos(loop, work, [](uv_work_t *work) {},
        [](uv_work_t *work, int status) { CompleteSmsSendWork(work, status); }, uv_qos_default);
    if (errCode != 0) {
        TELEPHONY_LOGE("OnSmsSendResult uv_queue_work_with_qos failed, errCode: %{public}d", errCode);
        delete pContext;
        delete work;
    }
    return;
}
} // namespace Telephony
} // namespace OHOS