/*
 * Copyright (C) 2021 Uniontech Software Technology Co., Ltd.
 *
 * Author:     wangchunlin<wangchunlin@uniontech.com>
 *
 * Maintainer: wangchunlin<wangchunlin@uniontech.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "gui/exhibition/matchresult/listview/grandsearchlistview.h"
#include "gui/exhibition/matchresult/listview/grandsearchlistmodel.h"

#include "global/matcheditem.h"
#include "global/builtinsearch.h"
#include "utils/utils.h"

#include "stubext.h"

#include <DStandardPaths>

#include <gtest/gtest.h>

#include <QPaintEvent>
#include <QEvent>
#include <QWidget>
#include <QSignalSpy>

using namespace testing;
using namespace GrandSearch;
DCORE_USE_NAMESPACE

TEST(GrandSearchListViewTest, constructor)
{
    GrandSearchListView *w = new GrandSearchListView;

    ASSERT_TRUE(w);
    ASSERT_TRUE(w->m_model);
    ASSERT_TRUE(w->m_delegate);

    delete w;
}

TEST(GrandSearchListViewTest, setMatchedItems)
{
    GrandSearchListView w;

    QString searchGroupName(GRANDSEARCH_GROUP_FOLDER);
    MatchedItem item;
    MatchedItems items{item, item};

    w.setMatchedItems(items);
    EXPECT_EQ(items, w.m_matchedItems);
}

TEST(GrandSearchListViewTest, addRow)
{
    GrandSearchListView w;

    stub_ext::StubExt stu;

    bool ut_call_setData = false;
    stu.set_lamda(ADDR(GrandSearchListView, setData), [&](){
        ut_call_setData = true;
    });

    MatchedItem item;
    w.addRow(item);
    EXPECT_TRUE(ut_call_setData);
}

TEST(GrandSearchListViewTest, addRow_level)
{
    GrandSearchListView w;

    stub_ext::StubExt stu;

    bool ut_call_insertRow = false;
    stu.set_lamda(ADDR(GrandSearchListView, insertRow), [&](){
        ut_call_insertRow = true;
        return 0;
    });

    MatchedItem item;
    w.addRow(item, 1);
    EXPECT_TRUE(ut_call_insertRow);
}

TEST(GrandSearchListViewTest, addRows)
{
    GrandSearchListView w;

    stub_ext::StubExt stu;

    bool ut_call_addRow = false;
    stu.set_lamda((void(GrandSearchListView::*)(const MatchedItem &))ADDR(GrandSearchListView, addRow), [&](){
        ut_call_addRow = true;
    });

    MatchedItem item;
    MatchedItems items{item, item};

    w.addRows(items);
    EXPECT_TRUE(ut_call_addRow);
}

TEST(GrandSearchListViewTest, addRows_level)
{
    GrandSearchListView w;

    stub_ext::StubExt stu;

    bool ut_call_insertRows = false;
    stu.set_lamda(ADDR(GrandSearchListView, insertRows), [&](){
        ut_call_insertRows = true;
    });

    MatchedItem item;
    MatchedItems items{item, item};

    w.addRows(items, 1);
    EXPECT_TRUE(ut_call_insertRows);
}

TEST(GrandSearchListViewTest, insertRow)
{
    GrandSearchListView w;

    stub_ext::StubExt stu;

    bool ut_call_addRow = false;
    stu.set_lamda((void(GrandSearchListView::*)(const MatchedItem &))ADDR(GrandSearchListView, addRow), [&](){
        ut_call_addRow = true;
    });

    bool ut_call_setData = false;
    stu.set_lamda(ADDR(GrandSearchListView, setData), [&](){
        ut_call_setData = true;
    });

    MatchedItem item;

    w.insertRow(100, item);
    EXPECT_TRUE(ut_call_addRow);
    EXPECT_FALSE(ut_call_setData);

    QStandardItem *newItem = new QStandardItem;
    w.m_model->insertRow(0, newItem);

    ut_call_addRow = false;
    ut_call_setData = false;

    w.insertRow(0, item);
    EXPECT_FALSE(ut_call_addRow);
    EXPECT_TRUE(ut_call_setData);
}

TEST(GrandSearchListViewTest, insertRows)
{
    GrandSearchListView w;

    stub_ext::StubExt stu;

    bool ut_call_addRows = false;
    stu.set_lamda((void(GrandSearchListView::*)(const MatchedItems &))ADDR(GrandSearchListView, addRows), [&](){
        ut_call_addRows = true;
    });

    bool ut_call_setData = false;
    stu.set_lamda(ADDR(GrandSearchListView, setData), [&](){
        ut_call_setData = true;
    });

    MatchedItem item;
    MatchedItems items{item, item};

    w.insertRows(100, items);
    EXPECT_TRUE(ut_call_addRows);
    EXPECT_FALSE(ut_call_setData);

    QStandardItem *newItem = new QStandardItem;
    w.m_model->insertRow(0, newItem);

    ut_call_addRows = false;
    ut_call_setData = false;

    w.insertRows(0, items);
    EXPECT_FALSE(ut_call_addRows);
    EXPECT_TRUE(ut_call_setData);
}

TEST(GrandSearchListViewTest, removeRows)
{
    GrandSearchListView w;

    QString searchGroupName(GRANDSEARCH_GROUP_FOLDER);
    MatchedItem item;
    MatchedItems items{item, item};

    w.setMatchedItems(items);

    int origin = w.m_model->rowCount();
    EXPECT_NE(origin, 0);

    w.removeRows(0, 2);
    origin = w.m_model->rowCount();
    EXPECT_EQ(origin, 0);
}

TEST(GrandSearchListViewTest, levelItemCount)
{
    GrandSearchListView w;

    QString searchGroupName(GRANDSEARCH_GROUP_FOLDER);
    MatchedItem item;
    MatchedItems items;

    // 添加分级元素
    QVariantHash showLevelHash({{GRANDSEARCH_PROPERTY_ITEM_LEVEL, GRANDSEARCH_PROPERTY_ITEM_LEVEL_SECOND}});
    item.extra = QVariant::fromValue(showLevelHash);
    items << item << item;

    // 添加普通数据
    item.extra.clear();
    items << item << item;

    w.setMatchedItems(items);

    int count = w.levelItemCount(GRANDSEARCH_PROPERTY_ITEM_LEVEL_SECOND);
    EXPECT_EQ(count, 2);
}

TEST(GrandSearchListViewTest, rowCount)
{
    GrandSearchListView w;

    QString searchGroupName(GRANDSEARCH_GROUP_FOLDER);
    MatchedItem item;
    MatchedItems items{item, item};

    w.setMatchedItems(items);

    int actual = w.rowCount();
    int expect = w.m_model->rowCount();
    EXPECT_EQ(actual, expect);
}

TEST(GrandSearchListViewTest, getThemeType)
{
    GrandSearchListView w;

    int actual = w.getThemeType();
    int expect = w.m_themeType;
    EXPECT_EQ(actual, expect);
}

TEST(GrandSearchListViewTest, clear)
{
    GrandSearchListView w;

    QString searchGroupName(GRANDSEARCH_GROUP_FOLDER);
    MatchedItem item;
    MatchedItems items{item, item};

    w.setMatchedItems(items);

    w.clear();
    EXPECT_EQ(w.m_model->rowCount(), 0);
}

TEST(GrandSearchListViewTest, updatePreviewItemState)
{
    GrandSearchListView list;
    bool preview = true;
    list.updatePreviewItemState(preview);
    EXPECT_TRUE(list.m_isPreviewItem);
}

TEST(GrandSearchListViewTest, isPreviewItem)
{
    GrandSearchListView list;
    list.m_isPreviewItem = true;
    bool result = list.isPreviewItem();
    EXPECT_TRUE(result);
}

TEST(GrandSearchListViewTest, mousePressEvent)
{
    GrandSearchListView w;

    QSignalSpy spyItemChanged(&w, &GrandSearchListView::sigCurrentItemChanged);
    QSignalSpy spyItemClicked(&w, &GrandSearchListView::sigItemClicked);

    QMouseEvent event1(QEvent::MouseButtonPress, QPointF(0, 0), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
    w.mousePressEvent(&event1);
    EXPECT_EQ(spyItemChanged.count(), 0);
    EXPECT_EQ(spyItemClicked.count(), 0);

    QString searchGroupName(GRANDSEARCH_GROUP_FOLDER);
    MatchedItem item;
    MatchedItems items{item, item};

    w.setMatchedItems(items);
    QModelIndex index = w.model()->index(0, 0);
    w.setCurrentIndex(index);

    stub_ext::StubExt stu;
    bool ut_call_open = false;
    stu.set_lamda(&Utils::openMatchedItem, [&](){
        ut_call_open = true;
        return true;
    });

    index = w.model()->index(1, 0);
    stu.set_lamda(VADDR(GrandSearchListView, indexAt), [&](){
        return index;
    });

    w.mousePressEvent(&event1);
    EXPECT_EQ(spyItemChanged.count(), 1);
    EXPECT_EQ(spyItemClicked.count(), 0);

    w.mousePressEvent(&event1);
    EXPECT_EQ(spyItemChanged.count(), 1);
    EXPECT_EQ(spyItemClicked.count(), 1);

    QMouseEvent event2(QEvent::MouseButtonPress, QPointF(0, 0), Qt::LeftButton, Qt::NoButton, Qt::ControlModifier);
    stu.set_lamda(&Utils::openMatchedItemWithCtrl, [](){
        return true;
    });

    w.mousePressEvent(&event2);
    EXPECT_EQ(spyItemChanged.count(), 1);
    EXPECT_EQ(spyItemClicked.count(), 2);
}

TEST(GrandSearchListViewTest, onSetThemeType)
{
    GrandSearchListView w;

    int actual = 0;
    w.onSetThemeType(actual);

    int expect = w.m_themeType;

    EXPECT_EQ(actual, expect);
}

TEST(GrandSearchListViewTest, cacheDir)
{
    GrandSearchListView w;

    QString expect = DStandardPaths::standardLocations(QStandardPaths::CacheLocation).value(0);
    QString actual = w.cacheDir();
    EXPECT_EQ(expect, actual);
}

TEST(GrandSearchListViewTest, event)
{
    GrandSearchListView w;

    QEvent event(QEvent::FocusIn);
    w.event(&event);
}

TEST(GrandSearchListViewTest, setData)
{
    GrandSearchListView w;

    QString searchGroupName(GRANDSEARCH_GROUP_FOLDER);
    MatchedItem item;
    w.addRow(item);

    QModelIndex index;
    w.setData(index, item);

    item.name = "QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ"
                "QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ";
    item.icon = "/test/abc.png";

    index = w.model()->index(0, 0);
    w.setData(index, item);

    QString tips = w.m_model->data(index, Qt::ToolTipRole).toString();
    EXPECT_EQ(tips, item.name);
    w.m_model->setData(index, QString(), Qt::ToolTipRole);

    item.name = "WW";
    item.icon = "abc.png";
    w.setData(index, item);
    tips = w.m_model->data(index, Qt::ToolTipRole).toString();
    EXPECT_TRUE(tips.isEmpty());
}

TEST(GrandSearchListViewTest, levelItemLastRow)
{
    GrandSearchListView w;

    QString searchGroupName(GRANDSEARCH_GROUP_FOLDER);
    MatchedItem item;
    MatchedItems items;

    // 添加分级元素
    QVariantHash showLevelHash({{GRANDSEARCH_PROPERTY_ITEM_LEVEL, GRANDSEARCH_PROPERTY_ITEM_LEVEL_SECOND}});
    item.extra = QVariant::fromValue(showLevelHash);
    items << item << item;

    // 添加普通数据
    item.extra.clear();
    items << item << item;

    w.setMatchedItems(items);

    int allCount = w.levelItemLastRow(0);
    int expect = w.m_model->rowCount();
    EXPECT_EQ(allCount, expect);


    allCount = w.levelItemLastRow(GRANDSEARCH_PROPERTY_ITEM_LEVEL_SECOND);
    EXPECT_EQ(allCount, 2);
}
