/*
 * Copyright (c) 2024 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 "common_method_modifier_test.h"

#include "modifier_test_base.h"
#include "modifiers_test_utils.h"
#include "core/interfaces/native/implementation/pixel_map_peer.h"
#include "core/interfaces/native/utility/converter.h"
#include "core/interfaces/native/utility/reverse_converter.h"
#include "generated/type_helpers.h"
#include "test/unittest/capi/utils/custom_node_builder_test_helper.h"
#include "test/unittest/capi/stubs/ace_pixelmap_stub.h"
#include "core/components_ng/pattern/overlay/overlay_manager.h"

using namespace testing;
using namespace testing::ext;

namespace OHOS::Ace::NG {
namespace {
const auto ATTRIBUTE_DRAG_PREVIEW_NAME = "dragPreview";
const auto ATTRIBUTE_DRAG_PREVIEW_DEFAULT_VALUE = std::nullopt;
const auto ATTRIBUTE_OVERLAY_NAME = "overlay";
const auto ATTRIBUTE_OVERLAY_TITLE_NAME = "title";
const auto ATTRIBUTE_OVERLAY_TITLE_DEFAULT_VALUE = "";
const auto ATTRIBUTE_OVERLAY_OPTIONS_NAME = "options";
const auto ATTRIBUTE_OVERLAY_OPTIONS_ALIGN_NAME = "align";
const auto ATTRIBUTE_OVERLAY_OPTIONS_ALIGN_DEFAULT_VALUE = "Alignment.Center";
const auto ATTRIBUTE_OVERLAY_OPTIONS_OFFSET_NAME = "offset";
const auto ATTRIBUTE_OVERLAY_OPTIONS_OFFSET_X_NAME = "x";
const auto ATTRIBUTE_OVERLAY_OPTIONS_OFFSET_X_DEFAULT_VALUE = "0.00px";
const auto ATTRIBUTE_OVERLAY_OPTIONS_OFFSET_Y_NAME = "y";
const auto ATTRIBUTE_OVERLAY_OPTIONS_OFFSET_Y_DEFAULT_VALUE = "0.00px";
}


class CommonMethodModifierTest12 : public ModifierTestBase<GENERATED_ArkUICommonMethodModifier,
    &GENERATED_ArkUINodeModifiers::getCommonMethodModifier,
    GENERATED_ARKUI_BLANK // test common methods on frameNode for Blank component
    > {
public:
    void *CreateNodeImpl() override
    {
        return nodeModifiers_->getBlankModifier()->construct(GetId(), 0);
    }

    static void SetUpTestCase()
    {
        ModifierTestBase::SetUpTestCase();
    }
};

//////////// DragPreview
/*
 * @tc.name: setDragPreviewTestDefaultValues
 * @tc.desc:
 * @tc.type: FUNC
 */
HWTEST_F(CommonMethodModifierTest12, setDragPreviewTestDefaultValues, TestSize.Level1)
{
    auto strResult = GetAttrValue<std::string>(node_, ATTRIBUTE_DRAG_PREVIEW_NAME);
    EXPECT_THAT(strResult, Eq(ATTRIBUTE_DRAG_PREVIEW_DEFAULT_VALUE));
}

/*
 * @tc.name: setDragPreviewTestCustomBuilder
 * @tc.desc:
 * @tc.type: FUNC
 */
HWTEST_F(CommonMethodModifierTest12, DISABLED_setDragPreviewTestCustomBuilder, TestSize.Level1)
{
    ASSERT_NE(modifier_->setDragPreview, nullptr);
    auto frameNode = reinterpret_cast<FrameNode*>(node_);
    ASSERT_NE(frameNode, nullptr);

    int callsCount = 0;
    CustomNodeBuilderTestHelper<CommonMethodModifierTest12> builderHelper(this, frameNode);
    const CustomNodeBuilder builder = builderHelper.GetBuilder();

    auto unionValue = Converter::ArkUnion<Opt_Union_CustomBuilder_DragItemInfo_String,
        CustomNodeBuilder>(builder);
    modifier_->setDragPreview(node_, &unionValue, nullptr);
    const DragDropInfo resultDragPreview = frameNode->GetDragPreview();

    EXPECT_EQ(builderHelper.GetCustomNode(), Referenced::RawPtr(resultDragPreview.customNode));
    EXPECT_EQ(builderHelper.GetCallsCountAsync(), ++callsCount);
}

/*
 * @tc.name: setDragPreviewTestDragItemInfo
 * @tc.desc:
 * @tc.type: FUNC
 */
HWTEST_F(CommonMethodModifierTest12, DISABLED_setDragPreviewTestDragItemInfo, TestSize.Level1)
{
    ASSERT_NE(modifier_->setDragPreview, nullptr);
    auto frameNode = reinterpret_cast<FrameNode*>(node_);
    ASSERT_NE(frameNode, nullptr);
    // CustomNodeBuilder
    int callsCount = 0;
    CustomNodeBuilderTestHelper<CommonMethodModifierTest12> builderHelper(this, frameNode);
    const CustomNodeBuilder builder = builderHelper.GetBuilder();
    // PixelMap
    Ace::RefPtr<Ace::PixelMap> expectedPixelMapRefPtr = AceType::MakeRefPtr<Ace::PixelMapStub>();
    image_PixelMapPeer pixelMapPeer;
    pixelMapPeer.pixelMap = expectedPixelMapRefPtr;
    Ark_image_PixelMap expectedPixelMap = &pixelMapPeer;
    // ExtraInfo
    std::string expectedExtraInfo{"extraInfo"};
    // struct DragItemInfo
    Ark_DragItemInfo dragItemInfo = {
        .builder = Converter::ArkValue<Opt_CustomNodeBuilder>(builder),
        .extraInfo = Converter::ArkValue<Opt_String>(expectedExtraInfo),
        .pixelMap = Converter::ArkValue<Opt_image_PixelMap>(expectedPixelMap)};

    auto unionValue = Converter::ArkUnion<Opt_Union_CustomBuilder_DragItemInfo_String,
        Ark_DragItemInfo>(dragItemInfo);
    modifier_->setDragPreview(node_, &unionValue, nullptr);
    const DragDropInfo resultDragPreview = frameNode->GetDragPreview();

    EXPECT_EQ(builderHelper.GetCustomNode(), Referenced::RawPtr(resultDragPreview.customNode));
    EXPECT_EQ(resultDragPreview.extraInfo, expectedExtraInfo);
    EXPECT_EQ(resultDragPreview.pixelMap, expectedPixelMapRefPtr);
    EXPECT_EQ(builderHelper.GetCallsCountAsync(), ++callsCount);
}

/*
 * @tc.name: setDragPreviewTestString
 * @tc.desc:
 * @tc.type: FUNC
 */
HWTEST_F(CommonMethodModifierTest12, DISABLED_setDragPreviewTestString, TestSize.Level1)
{
    ASSERT_NE(modifier_->setDragPreview, nullptr);
    auto frameNode = reinterpret_cast<FrameNode*>(node_);
    ASSERT_NE(frameNode, nullptr);

    std::string expectedString{"DragPreview_String"};
    auto arkExpectedString = Converter::ArkValue<Ark_String>(expectedString);

    auto unionValue = Converter::ArkUnion<Opt_Union_CustomBuilder_DragItemInfo_String, Ark_String>(arkExpectedString);
    modifier_->setDragPreview(node_, &unionValue, nullptr);

    const DragDropInfo resultDragPreview = frameNode->GetDragPreview();

    EXPECT_EQ(resultDragPreview.inspectorId, expectedString);
}

//////// AccessibilityVirtualNode
/*
 * @tc.name: setAccessibilityVirtualNodeTestAccessibilityVirtualNode
 * @tc.desc:
 * @tc.type: FUNC
 */
HWTEST_F(CommonMethodModifierTest12, setAccessibilityVirtualNodeTestAccessibilityVirtualNode, TestSize.Level1)
{
    ASSERT_NE(modifier_->setAccessibilityVirtualNode, nullptr);
    auto frameNode = reinterpret_cast<FrameNode*>(node_);
    ASSERT_NE(frameNode, nullptr);

    int callsCount = 0;
    CustomNodeBuilderTestHelper<CommonMethodModifierTest12> builderHelper(this, frameNode);
    const CustomNodeBuilder builder = builderHelper.GetBuilder();
    const auto arkBuilder = Converter::ArkValue<Opt_CustomNodeBuilder>(builder);
    modifier_->setAccessibilityVirtualNode(node_, &arkBuilder);
    EXPECT_EQ(builderHelper.GetCallsCountAsync(), ++callsCount);
}

/*
 * @tc.name: setOverlayTestDefaultValues
 * @tc.desc:
 * @tc.type: FUNC
 */
HWTEST_F(CommonMethodModifierTest12, setOverlayTestDefaultValues, TestSize.Level1)
{
    auto fullJson = GetJsonValue(node_);
    auto overlay = GetAttrObject(fullJson, ATTRIBUTE_OVERLAY_NAME);
    auto options = GetAttrObject(overlay, ATTRIBUTE_OVERLAY_OPTIONS_NAME);
    auto offset = GetAttrObject(options, ATTRIBUTE_OVERLAY_OPTIONS_OFFSET_NAME);

    auto title = GetAttrValue<std::string>(overlay, ATTRIBUTE_OVERLAY_TITLE_NAME);
    EXPECT_THAT(title, Eq(ATTRIBUTE_OVERLAY_TITLE_DEFAULT_VALUE));
    auto align = GetAttrValue<std::string>(options, ATTRIBUTE_OVERLAY_OPTIONS_ALIGN_NAME);
    EXPECT_THAT(align, Eq(ATTRIBUTE_OVERLAY_OPTIONS_ALIGN_DEFAULT_VALUE));
    auto x = GetAttrValue<std::string>(offset, ATTRIBUTE_OVERLAY_OPTIONS_OFFSET_X_NAME);
    EXPECT_THAT(x, Eq(ATTRIBUTE_OVERLAY_OPTIONS_OFFSET_X_DEFAULT_VALUE));
    auto y = GetAttrValue<std::string>(offset, ATTRIBUTE_OVERLAY_OPTIONS_OFFSET_Y_NAME);
    EXPECT_THAT(y, Eq(ATTRIBUTE_OVERLAY_OPTIONS_OFFSET_Y_DEFAULT_VALUE));
}

/*
 * @tc.name: setOverlayTestValidValues
 * @tc.desc:
 * @tc.type: FUNC
 */
HWTEST_F(CommonMethodModifierTest12, setOverlayTestValidValues, TestSize.Level1)
{
    ASSERT_NE(modifier_->setOverlay, nullptr);
    auto frameNode = reinterpret_cast<FrameNode*>(node_);
    ASSERT_NE(frameNode, nullptr);

    const std::vector<std::tuple<Ark_Alignment, std::string>> testPlan = {
        {ARK_ALIGNMENT_TOP_START, "Alignment.TopStart" },
        {ARK_ALIGNMENT_TOP, "Alignment.Top"},
        {ARK_ALIGNMENT_TOP_END, "Alignment.TopEnd"},
        {ARK_ALIGNMENT_START, "Alignment.Start"},
        {ARK_ALIGNMENT_CENTER, "Alignment.Center"},
        {ARK_ALIGNMENT_END, "Alignment.End"},
        {ARK_ALIGNMENT_BOTTOM_START, "Alignment.BottomStart"},
        {ARK_ALIGNMENT_BOTTOM, "Alignment.Bottom"},
        {ARK_ALIGNMENT_BOTTOM_END, "Alignment.BottomEnd"},
    };

    std::string expectedStr = "overlay string";
    auto unionStringValue = Converter::ArkUnion<Opt_Union_String_CustomBuilder_ComponentContent, Ark_String>(
        expectedStr, Converter::FC);
    Ark_OverlayOffset arkOverlayOffset = {
        .x = Converter::ArkValue<Opt_Float64>(5.),
        .y = Converter::ArkValue<Opt_Float64>(6.),
    };
    Ark_OverlayOptions arkOverlayOptions;
    arkOverlayOptions.offset = Converter::ArkValue<Opt_OverlayOffset>(arkOverlayOffset);

    for (auto [inputValue, expectedValue]: testPlan) {
        arkOverlayOptions.align = Converter::ArkValue<Opt_Alignment>(inputValue);
        auto optOverlayOptions = Converter::ArkValue<Opt_OverlayOptions>(arkOverlayOptions);
        modifier_->setOverlay(node_, &unionStringValue, &optOverlayOptions);
        auto fullJson = GetJsonValue(node_);
        auto overlay = GetAttrObject(fullJson, ATTRIBUTE_OVERLAY_NAME);
        auto options = GetAttrObject(overlay, ATTRIBUTE_OVERLAY_OPTIONS_NAME);
        auto resultValue = GetAttrValue<std::string>(options, ATTRIBUTE_OVERLAY_OPTIONS_ALIGN_NAME);
        EXPECT_THAT(resultValue, Eq(expectedValue)) << "Passed value is: " << expectedValue;
    }

    auto fullJson = GetJsonValue(node_);
    auto overlay = GetAttrObject(fullJson, ATTRIBUTE_OVERLAY_NAME);
    auto options = GetAttrObject(overlay, ATTRIBUTE_OVERLAY_OPTIONS_NAME);
    auto offset = GetAttrObject(options, ATTRIBUTE_OVERLAY_OPTIONS_OFFSET_NAME);

    auto title = GetAttrValue<std::string>(overlay, ATTRIBUTE_OVERLAY_TITLE_NAME);
    EXPECT_THAT(title, Eq(expectedStr));
    auto x = GetAttrValue<std::string>(offset, ATTRIBUTE_OVERLAY_OPTIONS_OFFSET_X_NAME);
    EXPECT_THAT(x, Eq("5.00vp"));
    auto y = GetAttrValue<std::string>(offset, ATTRIBUTE_OVERLAY_OPTIONS_OFFSET_Y_NAME);
    EXPECT_THAT(y, Eq("6.00vp"));

    // test CustomNodeBuilder
    CustomNodeBuilderTestHelper<CommonMethodModifierTest12> builderHelper(this, frameNode);
    auto unionCustomNodeBuilderValue = Converter::ArkUnion<Opt_Union_String_CustomBuilder_ComponentContent,
        CustomNodeBuilder>(builderHelper.GetBuilder());
    modifier_->setOverlay(node_, &unionCustomNodeBuilderValue, nullptr);
    EXPECT_EQ(builderHelper.GetCallsCountAsync(), 1);
}

}