/*
 * Copyright (c) 2023 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.
 */

#ifndef INPUTMETHOD_IMF_JSPANEL_H
#define INPUTMETHOD_IMF_JSPANEL_H

#include <mutex>
#include <uv.h>

#include "async_call.h"
#include "ffrt_block_queue.h"
#include "input_method_panel.h"
#include "js_callback_object.h"
#include "napi/native_api.h"
#include "napi/native_common.h"
#include "napi/native_node_api.h"
#include "native_engine/native_engine.h"
#include "native_engine/native_value.h"
#include "panel_deal_queue.h"

namespace OHOS {
namespace MiscServices {

struct JsPanelRect {
    static napi_value Write(napi_env env, const LayoutParams &layoutParams);
    static bool Read(napi_env env, napi_value object, LayoutParams &layoutParams);
};

struct JsEnhancedPanelRect {
    static bool Read(napi_env env, napi_value object, EnhancedLayoutParams &layoutParams);
};

struct JsHotArea {
    static bool Read(napi_env env, napi_value object, std::vector<Rosen::Rect> &hotAreas);
};

struct JsImmersiveEffect {
    static bool Read(napi_env env, napi_value object, ImmersiveEffect &effect);
};

class JsPanel {
public:
    JsPanel() = default;
    ~JsPanel();
    static napi_value Init(napi_env env);
    static napi_value SetUiContent(napi_env env, napi_callback_info info);
    static napi_value Resize(napi_env env, napi_callback_info info);
    static napi_value MoveTo(napi_env env, napi_callback_info info);
    static napi_value Show(napi_env env, napi_callback_info info);
    static napi_value Hide(napi_env env, napi_callback_info info);
    static napi_value ChangeFlag(napi_env env, napi_callback_info info);
    static napi_value SetPrivacyMode(napi_env env, napi_callback_info info);
    static napi_value Subscribe(napi_env env, napi_callback_info info);
    static napi_value UnSubscribe(napi_env env, napi_callback_info info);
    static napi_value AdjustPanelRect(napi_env env, napi_callback_info info);
    static napi_value UpdatePanelRect(napi_env env, napi_callback_info info);
    static napi_value UpdatePanelRectSync(napi_env env, napi_callback_info info);
    static napi_value UpdateRegion(napi_env env, napi_callback_info info);
    static napi_value StartMoving(napi_env env, napi_callback_info info);
    static napi_value GetDisplayId(napi_env env, napi_callback_info info);
    void SetNative(const std::shared_ptr<InputMethodPanel> &panel);
    std::shared_ptr<InputMethodPanel> GetNative();
    static napi_value SetImmersiveMode(napi_env env, napi_callback_info info);
    static napi_value GetImmersiveMode(napi_env env, napi_callback_info info);
    static napi_value SetImmersiveEffect(napi_env env, napi_callback_info info);
    static napi_value SetKeepScreenOn(napi_env env, napi_callback_info info);
    static napi_value SetSystemPanelButtonColor(napi_env env, napi_callback_info info);
    static napi_value GetSystemPanelCurrentInsets(napi_env env, napi_callback_info info);
    static napi_value SetShadow(napi_env env, napi_callback_info info);

private:
    struct PanelContentContext : public AsyncCall::Context {
        LayoutParams layoutParams = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 } };
        EnhancedLayoutParams enhancedLayoutParams;
        HotAreas hotAreas;
        std::vector<Rosen::Rect> hotArea;
        bool isEnhancedCall{ false };
        PanelFlag panelFlag = PanelFlag::FLG_FIXED;
        std::string path = "";
        uint32_t width = 0;
        uint32_t height = 0;
        int32_t x = 0;
        int32_t y = 0;
        uint64_t displayId = 0;
        bool isKeepScreenOn = false;
        SystemPanelInsets systemPanelInsets = {0, 0, 0};
        std::string fillColor;
        std::string backgroundColor;
        std::shared_ptr<InputMethodPanel> inputMethodPanel = nullptr;
        std::shared_ptr<NativeReference> contentStorage = nullptr;
        JsEventInfo info;
        PanelContentContext(napi_env env, napi_callback_info info) : Context(nullptr, nullptr)
        {
            napi_value self = nullptr;
            napi_status status = napi_get_cb_info(env, info, 0, nullptr, &self, nullptr);
            CHECK_RETURN_VOID((status == napi_ok) && (self != nullptr), "get callback info failed.");
            void *native = nullptr;
            status = napi_unwrap(env, self, &native);
            CHECK_RETURN_VOID((status == napi_ok) && (native != nullptr), "get jsPanel failed.");
            inputMethodPanel = reinterpret_cast<JsPanel *>(native)->GetNative();
        };
        PanelContentContext(InputAction input, OutputAction output) : Context(std::move(input), std::move(output)){};
        napi_status operator()(napi_env env, size_t argc, napi_value *argv, napi_value self) override
        {
            CHECK_RETURN(self != nullptr, "self is nullptr", napi_invalid_arg);
            return Context::operator()(env, argc, argv, self);
        }
        napi_status operator()(napi_env env, napi_value *result) override
        {
            if (status_ != napi_ok) {
                output_ = nullptr;
                return status_;
            }
            return Context::operator()(env, result);
        }
    };
    static napi_value JsNew(napi_env env, napi_callback_info info);
    static std::shared_ptr<InputMethodPanel> UnwrapPanel(napi_env env, napi_value thisVar);

    static bool IsEnhancedAdjust(napi_env env, napi_value *argv, size_t argc);
    static bool IsPanelFlagValid(napi_env env, PanelFlag panelFlag, bool isEnhancedCalled);
    static napi_status ParsePanelFlag(napi_env env, napi_value *argv, PanelFlag &panelFlag, bool isEnhancedCalled);
    static napi_status CheckParam(
        napi_env env, size_t argc, napi_value *argv, std::shared_ptr<PanelContentContext> ctxt);
    static napi_status CheckEnhancedParam(
        napi_env env, size_t argc, napi_value *argv, std::shared_ptr<PanelContentContext> ctxt);
    static void AdjustLayoutParam(std::shared_ptr<PanelContentContext> ctxt);
    static void AdjustEnhancedLayoutParam(std::shared_ptr<PanelContentContext> ctxt);
    static napi_value WriteCurrentInsetsOutput(napi_env env, SystemPanelInsets systemPanelInsets);
    static napi_status CheckButtonColor(napi_env env, std::shared_ptr<PanelContentContext> ctxt, napi_value *argv);
    static napi_status CheckSetUiContentParams(napi_env env, size_t argc, std::shared_ptr<PanelContentContext> ctxt,
        napi_value *argv);

    static const std::string CLASS_NAME;
    static constexpr size_t ARGC_MAX = 6;
    std::shared_ptr<InputMethodPanel> inputMethodPanel_ = nullptr;

    static std::mutex panelConstructorMutex_;
    static thread_local napi_ref panelConstructorRef_;
};
} // namespace MiscServices
} // namespace OHOS

#endif //INPUTMETHOD_IMF_JSPANEL_H