/*
    SPDX-FileCopyrightText: 2017 Elvis Angelaccio <elvis.angelaccio@kde.org>
    SPDX-FileCopyrightText: 2018 Michael Heidelbach <ottwolt@gmail.com>

    SPDX-License-Identifier: LGPL-2.1-or-later
*/

#include "ktooltipwidgettest.h"

#include <KToolTipWidget>

#include <QLayout>
#include <QStyle>
#include <QLabel>
#include <QLineEdit>
#include <QSignalSpy>
#include <QScreen>
#include <QTest>

void KToolTipWidgetTest::initTestCase()
{
    m_screenGeometry = QGuiApplication::primaryScreen()->geometry();
}

void KToolTipWidgetTest::showTooltipShouldShowContent()
{
    KToolTipWidget tooltip;
    QLabel label;

    tooltip.showAt(QPoint(10, 10), &label, nullptr);
    QVERIFY(tooltip.isVisible());
    QVERIFY(label.isVisible());
}

void KToolTipWidgetTest::hideLaterShouldHideAfterDelay()
{
    KToolTipWidget tooltip;
    QLabel label;

    tooltip.showAt(QPoint(10, 10), &label, nullptr);
    QVERIFY(tooltip.isVisible());
    QVERIFY(label.isVisible());

    tooltip.hideLater();
    QVERIFY(tooltip.isVisible());
    QVERIFY(label.isVisible());

    QSignalSpy spy(&tooltip, &KToolTipWidget::hidden);
    connect(&tooltip, &KToolTipWidget::hidden, this, [&]() {
        QVERIFY(tooltip.isHidden());
        QVERIFY(!label.isVisible());
    });

    QEventLoop eventLoop;
    connect(&tooltip, &KToolTipWidget::hidden, &eventLoop, &QEventLoop::quit);
    QCOMPARE(eventLoop.exec(), 0);
    QCOMPARE(spy.count(), 1);
}

void KToolTipWidgetTest::setZeroDelayShouldHideImmediately()
{
    KToolTipWidget tooltip;
    QLabel label;

    tooltip.setHideDelay(0);
    tooltip.showAt(QPoint(10, 10), &label, nullptr);
    QVERIFY(tooltip.isVisible());
    QVERIFY(label.isVisible());

    tooltip.hideLater();
    QVERIFY(tooltip.isHidden());
    QVERIFY(!label.isVisible());
}

void KToolTipWidgetTest::shouldHideImmediatelyIfContentDestroyed()
{
    KToolTipWidget tooltip;
    auto lineEdit = new QLineEdit();

    tooltip.showAt(QPoint(10, 10), lineEdit, nullptr);
    QVERIFY(tooltip.isVisible());

    delete lineEdit;
    QVERIFY(tooltip.isHidden());
}

void KToolTipWidgetTest::shouldNotTakeOwnershipOfContent()
{
    auto parent = new QWidget();
    auto label = new QLabel(parent);
    auto tooltip = new KToolTipWidget();

    tooltip->showAt(QPoint(10, 10), label, nullptr);
    QCOMPARE(label->parent(), tooltip);
    QVERIFY(label->isVisible());

    QSignalSpy spy(label, &QWidget::destroyed);
    delete tooltip;
    QVERIFY(!label->isVisible());
    QCOMPARE(label->parent(), parent);
    QCOMPARE(spy.count(), 0);

    delete parent;
    QCOMPARE(spy.count(), 1);
}

void KToolTipWidgetTest::shouldNotObscureTarget_data()
{
    qDebug() << "Style used" << QApplication::style()->objectName();

    QTest::addColumn<QPoint>("position");
    QTest::addColumn<QString>("content");

    const QMap<QString,QPoint> positions{
        {QStringLiteral("topleft"), QPoint(m_offset, m_offset)},
        {QStringLiteral("topright"), QPoint(-m_offset, m_offset)},
        {QStringLiteral("bottomright"), QPoint(-m_offset, -m_offset)},
        {QStringLiteral("bottomleft"), QPoint(m_offset, -m_offset)},
        {QStringLiteral("centered"),
            QPoint(m_screenGeometry.width() / 2, m_screenGeometry.height() / 2)}
    };

    QMapIterator<QString, QPoint> i(positions);
    while (i.hasNext()) {
        i.next();
        QTest::newRow(qPrintable(QStringLiteral("small/%1").arg(i.key())) )
            << i.value()
            << QStringLiteral("dummy text");

        QTest::newRow(qPrintable(QStringLiteral("multiline/%1").arg(i.key())))
            << i.value()
            << QStringLiteral("dummy text\nLine 1\nLine 2\nLine 3");

        QTest::newRow(qPrintable(QStringLiteral("one long line/%1").arg(i.key())))
            << i.value()
            << QStringLiteral(
                "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam nec felis sed elit auctor lobortis non a urna. Quisque non posuere mauris. Suspendisse potenti. In diam leo, lobortis at placerat nec, sagittis at tortor. Pellentesque scelerisque enim vel elementum scelerisque. Integer eget lectus vitae lorem pulvinar hendrerit. Suspendisse auctor sapien vel semper porta. Vestibulum fringilla aliquet tincidunt. Maecenas mollis mauris et erat viverra mollis. Proin suscipit felis nisi, a dapibus est hendrerit euismod. Suspendisse quis faucibus quam. Fusce eu cursus magna, et egestas purus. Duis enim sapien, feugiat id facilisis non, rhoncus ut lectus. Aliquam at nisi vel ligula interdum ultricies. Donec condimentum ante quam, eu congue lectus pulvinar in. Cras interdum, neque quis fermentum consequat, lectus tellus eleifend turpis."
            );

        if (m_screenGeometry.width() >= 1600 && m_screenGeometry.height() >= 900) {
            QTest::newRow(qPrintable(QStringLiteral("super large/%1").arg(i.key())))
                << i.value()
                << QStringLiteral(
                    "dummy 0 text\nLine 1\nLine 2\nLine 3"
                    "dummy 1 text\nLine 1\nLine 2\nLine 3"
                    "dummy 2 text\nLine 1\nLine 2\nLine 3"
                    "dummy 3 text\nLine 1\nLine 2\nLine 3"
                    "dummy 4 text\nLine 1\nLine 2\nLine 3"

                    "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam nec felis sed elit auctor lobortis non a urna. Quisque non posuere mauris. Suspendisse potenti. In diam leo, lobortis at placerat nec, sagittis at tortor. Pellentesque scelerisque enim vel elementum scelerisque. Integer eget lectus vitae lorem pulvinar hendrerit. Suspendisse auctor sapien vel semper porta. Vestibulum fringilla aliquet tincidunt. Maecenas mollis mauris et erat viverra mollis. Proin suscipit felis nisi, a dapibus est hendrerit euismod. Suspendisse quis faucibus quam. Fusce eu cursus magna, et egestas purus. Duis enim sapien, feugiat id facilisis non, rhoncus ut lectus. Aliquam at nisi vel ligula interdum ultricies. Donec condimentum ante quam, eu congue lectus pulvinar in. Cras interdum, neque quis fermentum consequat, lectus tellus eleifend turpis."
                );
        }
    }
}

void KToolTipWidgetTest::shouldNotObscureTarget()
{
    QFETCH(QPoint, position);
    QFETCH(QString, content);

    QWidget* containerWidget = new QWidget();
    const int margin = containerWidget->style()->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth);
    QLabel* targetWidget = new QLabel(QStringLiteral("dummy file"));
    QLayout* layout = new QHBoxLayout(containerWidget);
    layout->addWidget(targetWidget);

    containerWidget->adjustSize();
    containerWidget->move(
        position.x() >= 0
            ? position.x()
            : m_screenGeometry.right() + position.x() - containerWidget->width(),
        position.y() >= 0
            ? position.y()
            : m_screenGeometry.bottom() + position.y() - containerWidget->height()
    );
    containerWidget->show();
    QVERIFY(QTest::qWaitForWindowExposed(containerWidget));
    QVERIFY(targetWidget->isVisible());

    QRect targetRect = QRect(targetWidget->frameGeometry());
    targetRect.moveTo(targetWidget->mapToGlobal(QPoint(0, 0)));

    QLabel* contentWidget = new QLabel(content);

    QVERIFY2(containerWidget->windowHandle(), "Container's window handle is invalid");
    KToolTipWidget tooltipWidget;
    tooltipWidget.showBelow(targetRect, contentWidget, containerWidget->windowHandle());
    QVERIFY(QTest::qWaitForWindowExposed(&tooltipWidget));
    const QRect tooltipRect = tooltipWidget.frameGeometry();

    qDebug() << QStringLiteral("tooltip: %1x%2 x=%3, y=%4")
        .arg(tooltipRect.width())
        .arg(tooltipRect.height())
        .arg(tooltipRect.left())
        .arg(tooltipRect.top());
    qDebug() << QStringLiteral("target:  %1x%2 x=%3, y=%4")
        .arg(targetRect.width())
        .arg(targetRect.height())
        .arg(targetRect.left())
        .arg(targetRect.top());

    QVERIFY2(!tooltipRect.intersects(targetRect), "Target obscured");
    QCOMPARE(tooltipRect.intersected(m_screenGeometry), tooltipRect);

    // Check margins
    if (tooltipRect.bottom() <  targetRect.top()) {
        QCOMPARE(margin, targetRect.top() - tooltipRect.bottom());
    } else if (tooltipRect.top() > targetRect.bottom()) {
        QCOMPARE(margin, tooltipRect.top() - targetRect.bottom());
    } else if (tooltipRect.right() < targetRect.left()) {
        QCOMPARE(margin, targetRect.left() - tooltipRect.right());
    } else if (tooltipRect.left() > targetRect.right() ) {
        QCOMPARE(margin, tooltipRect.left() - targetRect.right());
    }

    tooltipWidget.hide();
    QVERIFY(tooltipWidget.isHidden());

    delete contentWidget;
    delete containerWidget;
}


QTEST_MAIN(KToolTipWidgetTest)


