#include <QGuiApplication>
#include <QSignalSpy>
#include <QtTest>

#include "shadowed-rectangle.h"
#include "scenegraph/painted-rectangle-item.h"

class TestableShadowedRectangle : public ShadowedRectangle
{
public:
    using ShadowedRectangle::ShadowedRectangle;
    using ShadowedRectangle::componentComplete;
    using ShadowedRectangle::softwareItem;
};

class shadowed_rectangle_test : public QObject
{
    Q_OBJECT

private slots:
    void groupedPropertiesExposeDefaultsAndEmitOnChange();
    void cornersGroupFallsBackToGlobalRadius();
    void rectanglePropertiesEmitOnlyOnRealChanges();
    void softwareRenderTypeCreatesFallbackItem();
};

void shadowed_rectangle_test::groupedPropertiesExposeDefaultsAndEmitOnChange()
{
    BorderGroup border;
    QCOMPARE(border.width(), 0.0);
    QCOMPARE(border.color(), QColor(Qt::black));
    QVERIFY(!border.isEnabled());

    QSignalSpy borderSpy(&border, &BorderGroup::changed);
    border.setWidth(0.0);
    border.setColor(QColor(Qt::black));
    QCOMPARE(borderSpy.count(), 0);

    border.setWidth(2.5);
    QCOMPARE(border.width(), 2.5);
    QVERIFY(border.isEnabled());
    QCOMPARE(borderSpy.count(), 1);

    border.setColor(QColor(Qt::red));
    QCOMPARE(border.color(), QColor(Qt::red));
    QCOMPARE(borderSpy.count(), 2);

    ShadowGroup shadow;
    QCOMPARE(shadow.size(), 0.0);
    QCOMPARE(shadow.xOffset(), 0.0);
    QCOMPARE(shadow.yOffset(), 0.0);
    QCOMPARE(shadow.color(), QColor(Qt::black));

    QSignalSpy shadowSpy(&shadow, &ShadowGroup::changed);
    shadow.setSize(12.0);
    shadow.setXOffset(3.0);
    shadow.setYOffset(-4.0);
    shadow.setColor(QColor(Qt::blue));

    QCOMPARE(shadow.size(), 12.0);
    QCOMPARE(shadow.xOffset(), 3.0);
    QCOMPARE(shadow.yOffset(), -4.0);
    QCOMPARE(shadow.color(), QColor(Qt::blue));
    QCOMPARE(shadowSpy.count(), 4);
}

void shadowed_rectangle_test::cornersGroupFallsBackToGlobalRadius()
{
    CornersGroup corners;
    QCOMPARE(corners.topLeft(), -1.0);
    QCOMPARE(corners.topRight(), -1.0);
    QCOMPARE(corners.bottomLeft(), -1.0);
    QCOMPARE(corners.bottomRight(), -1.0);
    QCOMPARE(corners.toVector4D(6.0f), QVector4D(6.0f, 6.0f, 6.0f, 6.0f));

    QSignalSpy cornersSpy(&corners, &CornersGroup::changed);
    corners.setTopLeft(1.0);
    corners.setTopRight(2.0);
    corners.setBottomLeft(3.0);
    corners.setBottomRight(4.0);

    QCOMPARE(cornersSpy.count(), 4);
    QCOMPARE(corners.toVector4D(6.0f), QVector4D(4.0f, 2.0f, 3.0f, 1.0f));
}

void shadowed_rectangle_test::rectanglePropertiesEmitOnlyOnRealChanges()
{
    TestableShadowedRectangle rectangle;
    QVERIFY(rectangle.border() != nullptr);
    QVERIFY(rectangle.shadow() != nullptr);
    QVERIFY(rectangle.corners() != nullptr);
    QCOMPARE(rectangle.border(), rectangle.border());
    QCOMPARE(rectangle.shadow(), rectangle.shadow());
    QCOMPARE(rectangle.corners(), rectangle.corners());

    QCOMPARE(rectangle.radius(), 0.0);
    QCOMPARE(rectangle.color(), QColor(Qt::white));
    QVERIFY(rectangle.pureColor());
    QCOMPARE(rectangle.startColor(), QColor(Qt::white));
    QCOMPARE(rectangle.endColor(), QColor(Qt::white));
    QCOMPARE(rectangle.angle(), 0.0);
    QCOMPARE(rectangle.renderType(), ShadowedRectangle::Auto);
    QVERIFY(!rectangle.isSoftwareRendering());

    QSignalSpy radiusSpy(&rectangle, &ShadowedRectangle::radiusChanged);
    QSignalSpy colorSpy(&rectangle, &ShadowedRectangle::colorChanged);
    QSignalSpy pureColorSpy(&rectangle, &ShadowedRectangle::pureColorChanged);
    QSignalSpy startColorSpy(&rectangle, &ShadowedRectangle::startColorChanged);
    QSignalSpy endColorSpy(&rectangle, &ShadowedRectangle::endColorChanged);
    QSignalSpy angleSpy(&rectangle, &ShadowedRectangle::angleChanged);
    QSignalSpy renderTypeSpy(&rectangle, &ShadowedRectangle::renderTypeChanged);

    rectangle.setRadius(0.0);
    rectangle.setColor(QColor(Qt::white));
    rectangle.setPureColor(true);
    rectangle.setStartColor(QColor(Qt::white));
    rectangle.setEndColor(QColor(Qt::white));
    rectangle.setAngle(0.0);
    rectangle.setRenderType(ShadowedRectangle::Auto);

    QCOMPARE(radiusSpy.count(), 0);
    QCOMPARE(colorSpy.count(), 0);
    QCOMPARE(pureColorSpy.count(), 0);
    QCOMPARE(startColorSpy.count(), 0);
    QCOMPARE(endColorSpy.count(), 0);
    QCOMPARE(angleSpy.count(), 0);
    QCOMPARE(renderTypeSpy.count(), 0);

    rectangle.setRadius(8.0);
    rectangle.setColor(QColor(Qt::green));
    rectangle.setPureColor(false);
    rectangle.setStartColor(QColor(Qt::yellow));
    rectangle.setEndColor(QColor(Qt::cyan));
    rectangle.setAngle(90.0);
    rectangle.setRenderType(ShadowedRectangle::Software);

    QCOMPARE(rectangle.radius(), 8.0);
    QCOMPARE(rectangle.color(), QColor(Qt::green));
    QVERIFY(!rectangle.pureColor());
    QCOMPARE(rectangle.startColor(), QColor(Qt::yellow));
    QCOMPARE(rectangle.endColor(), QColor(Qt::cyan));
    QVERIFY(!qFuzzyIsNull(rectangle.angle()));
    QCOMPARE(rectangle.renderType(), ShadowedRectangle::Software);
    QVERIFY(rectangle.isSoftwareRendering());

    QCOMPARE(radiusSpy.count(), 1);
    QCOMPARE(colorSpy.count(), 1);
    QCOMPARE(pureColorSpy.count(), 1);
    QCOMPARE(startColorSpy.count(), 1);
    QCOMPARE(endColorSpy.count(), 1);
    QCOMPARE(angleSpy.count(), 1);
    QCOMPARE(renderTypeSpy.count(), 1);

    rectangle.setRenderType(ShadowedRectangle::Auto);
    QCOMPARE(renderTypeSpy.count(), 2);
    QVERIFY(!rectangle.isSoftwareRendering());
}

void shadowed_rectangle_test::softwareRenderTypeCreatesFallbackItem()
{
    TestableShadowedRectangle rectangle;
    rectangle.setWidth(80.0);
    rectangle.setHeight(30.0);
    rectangle.setRenderType(ShadowedRectangle::Software);

    QVERIFY(rectangle.softwareItem() == nullptr);
    QVERIFY(rectangle.flags().testFlag(QQuickItem::ItemHasContents));

    rectangle.componentComplete();

    PaintedRectangleItem *softwareItem = rectangle.softwareItem();
    QVERIFY(softwareItem != nullptr);
    QCOMPARE(softwareItem->parentItem(), &rectangle);
    QCOMPARE(rectangle.childItems().size(), 1);
    QCOMPARE(rectangle.childItems().constFirst(), static_cast<QQuickItem *>(softwareItem));
    QCOMPARE(softwareItem->z(), -99.0);
    QCOMPARE(softwareItem->width(), 80.0);
    QCOMPARE(softwareItem->height(), 30.0);
    QVERIFY(!rectangle.flags().testFlag(QQuickItem::ItemHasContents));

    rectangle.setWidth(120.0);
    rectangle.setHeight(45.0);
    QCOMPARE(softwareItem->width(), 120.0);
    QCOMPARE(softwareItem->height(), 45.0);
}

int main(int argc, char *argv[])
{
    qputenv("QT_QPA_PLATFORM", "offscreen");
    qputenv("QT_QPA_PLATFORMTHEME", "generic");
    qputenv("QT_FATAL_WARNINGS", "0");
    qputenv("QT_LOGGING_RULES", "qt.qpa.*=false");

    QGuiApplication app(argc, argv);
    shadowed_rectangle_test testCase;
    return QTest::qExec(&testCase, argc, argv);
}

#include "test-shadowed-rectangle.moc"
