// Copyright (C) 2022 The Qt Company Ltd.
// Copyright (C) 2020 Alexey Edelev <semlanik@gmail.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0

#include "nestedmessages.qpb.h"
#include "externalpackage.qpb.h"

#include <QTest>
#include <qtprotobuftestscommon.h>
#include <QProtobufSerializer>

using namespace qtprotobufnamespace::tests::nested;

class QtProtobufNestedTest : public QObject
{
    Q_OBJECT
private slots:
    void init()
    {
        m_serializer.reset(new QProtobufSerializer);
    }
    void NestedMessageTest();
    void SimpleTest();
    void SerializationTest();
    void DeserializationTest();
    void NeighborTest();
    void NestedNoFieldsTest();
    void NestedCyclingTest();
    void UnusedNestedMessageTest();
private:
    std::unique_ptr<QProtobufSerializer> m_serializer;
};

void QtProtobufNestedTest::NestedMessageTest()
{
    qProtobufAssertMessagePropertyRegistered<NestedFieldMessage::NestedMessage, QtProtobuf::sint32>(1, "QtProtobuf::sint32", "testFieldInt");
}

void QtProtobufNestedTest::SimpleTest()
{
    const char *propertyName = "nested";

    qProtobufAssertMessagePropertyRegistered<NestedFieldMessage, NestedFieldMessage::NestedMessage*>(2, "qtprotobufnamespace::tests::nested::NestedFieldMessage::NestedMessage*", "nested");

    NestedFieldMessage::NestedMessage nestedMsg;
    nestedMsg.setTestFieldInt(15);

    NestedFieldMessage test;
    test.setNested(nestedMsg);
    QCOMPARE(test.nested().testFieldInt(), 15);

    nestedMsg.setTestFieldInt(65555);
    QVERIFY(test.setProperty(propertyName,
                             QVariant::fromValue<NestedFieldMessage::NestedMessage *>(
                                     new NestedFieldMessage::NestedMessage(nestedMsg))));
    QCOMPARE(*(test.property(propertyName).value<NestedFieldMessage::NestedMessage *>()),
             nestedMsg);
    QCOMPARE(test.nested(), nestedMsg);

    qProtobufAssertMessagePropertyRegistered<NestedFieldMessage2::NestedMessageLevel1, NestedFieldMessage2::NestedMessageLevel1::NestedMessageLevel2*>(1, "qtprotobufnamespace::tests::nested::NestedFieldMessage2::NestedMessageLevel1::NestedMessageLevel2*", "nested");

    NestedFieldMessage2::NestedMessageLevel1::NestedMessageLevel2 level2;
    level2.setTestFieldInt(20);
    NestedFieldMessage2::NestedMessageLevel1 level1;
    level1.setNested(level2);
    QCOMPARE(level1.nested().testFieldInt(), 20);

    level2.setTestFieldInt(55);
    QVERIFY(level1.setProperty(
            propertyName,
            QVariant::fromValue<NestedFieldMessage2::NestedMessageLevel1::NestedMessageLevel2 *>(
                    new NestedFieldMessage2::NestedMessageLevel1::NestedMessageLevel2(level2))));
    QCOMPARE(*(level1.property(propertyName)
                       .value<NestedFieldMessage2::NestedMessageLevel1::NestedMessageLevel2 *>()),
             level2);
    QCOMPARE(level1.nested(), level2);

    qProtobufAssertMessagePropertyRegistered<NestedFieldMessage2, NestedFieldMessage2::NestedMessageLevel1::NestedMessageLevel2*>(3, "qtprotobufnamespace::tests::nested::NestedFieldMessage2::NestedMessageLevel1::NestedMessageLevel2*", "nested2");

    NestedFieldMessage2 test2;

    level2.setTestFieldInt(55);
    level1.setNested(level2);
    test2.setNested1(level1);

    level2.setTestFieldInt(20);
    test2.setNested2(level2);

    QCOMPARE(test2.nested1().nested().testFieldInt(), 55);
    QCOMPARE(test2.nested2().testFieldInt(), 20);

    level2.setTestFieldInt(65);
    level1.setNested(level2);

    QVERIFY(test2.setProperty("nested1",
                              QVariant::fromValue<NestedFieldMessage2::NestedMessageLevel1 *>(
                                      new NestedFieldMessage2::NestedMessageLevel1(level1))));
    QCOMPARE(*(test2.property("nested1").value<NestedFieldMessage2::NestedMessageLevel1 *>()),
             level1);
    QCOMPARE(test2.nested1(), level1);

    level2.setTestFieldInt(75);
    QVERIFY(test2.setProperty(
            "nested2",
            QVariant::fromValue<NestedFieldMessage2::NestedMessageLevel1::NestedMessageLevel2 *>(
                    new NestedFieldMessage2::NestedMessageLevel1::NestedMessageLevel2(level2))));
    QCOMPARE(*(test2.property("nested2")
                       .value<NestedFieldMessage2::NestedMessageLevel1::NestedMessageLevel2 *>()),
             level2);
    QCOMPARE(test2.nested2(), level2);

    QCOMPARE(test.propertyOrdering.getMessageFullName(),
             "qtprotobufnamespace.tests.nested.NestedFieldMessage");
    QCOMPARE(nestedMsg.propertyOrdering.getMessageFullName(),
             "qtprotobufnamespace.tests.nested.NestedFieldMessage.NestedMessage");
}

void QtProtobufNestedTest::SerializationTest()
{
    NestedFieldMessage::NestedMessage nested;
    nested.setTestFieldInt(15);

    QByteArray result = nested.serialize(m_serializer.get());
    QCOMPARE(result.size(), 2);
    QCOMPARE(result.toHex().toStdString().c_str(), "081e");

    NestedFieldMessage test;
    test.setTestFieldInt(10);
    test.setNested(nested);

    result = test.serialize(m_serializer.get());
    QVERIFY(result == QByteArray::fromHex("1202081e0814")
                || result == QByteArray::fromHex("08141202081e"));

    NestedFieldMessage2::NestedMessageLevel1::NestedMessageLevel2 level2;
    level2.setTestFieldInt(10);
    NestedFieldMessage2::NestedMessageLevel1 level1;
    level1.setNested(level2);
    result = level1.serialize(m_serializer.get());
    QCOMPARE(result.toHex().toStdString().c_str(), "0a020814");

    NestedFieldMessage2 test2;
    level2.setTestFieldInt(10);
    level1.setNested(level2);
    test2.setNested1(level1);
    level2.setTestFieldInt(15);
    test2.setNested2(level2);
    result = test2.serialize(m_serializer.get());
    QVERIFY(result == QByteArray::fromHex("1a02081e12040a020814")
                || result == QByteArray::fromHex("12040a0208141a02081e"));

    NeighborNested neigbor;
    nested.setTestFieldInt(15);
    level2.setTestFieldInt(20);
    neigbor.setNeighborNested(nested);
    neigbor.setNeighborNested2(level2);
    result = neigbor.serialize(m_serializer.get());
    QVERIFY(result == QByteArray::fromHex("120208280a02081e")
                || result == QByteArray::fromHex("0a02081e12020828"));
}

void QtProtobufNestedTest::DeserializationTest()
{
    NestedFieldMessage::NestedMessage nested;

    nested.deserialize(m_serializer.get(), QByteArray::fromHex("081e"));
    QCOMPARE(nested.testFieldInt(), 15);

    NestedFieldMessage test;
    test.deserialize(m_serializer.get(), QByteArray::fromHex("1202081e0814"));
    QCOMPARE(test.nested().testFieldInt(), 15);

    NestedFieldMessage2::NestedMessageLevel1 level1;
    level1.deserialize(m_serializer.get(), QByteArray::fromHex("0a020814"));
    QCOMPARE(level1.nested().testFieldInt(), 10);

    NestedFieldMessage2 test2;
    test2.deserialize(m_serializer.get(), QByteArray::fromHex("1a02081e12040a020814"));
    QCOMPARE(test2.nested1().nested().testFieldInt(), 10);
    QCOMPARE(test2.nested2().testFieldInt(), 15);

    NeighborNested neigbor;
    neigbor.deserialize(m_serializer.get(), QByteArray::fromHex("120208280a02081e"));
    QCOMPARE(neigbor.neighborNested().testFieldInt(), 15);
    QCOMPARE(neigbor.neighborNested2().testFieldInt(), 20);
}


void QtProtobufNestedTest::NeighborTest()
{
    qProtobufAssertMessagePropertyRegistered<NeighborNested, NestedFieldMessage::NestedMessage*>(1, "qtprotobufnamespace::tests::nested::NestedFieldMessage::NestedMessage*", "neighborNested");
    qProtobufAssertMessagePropertyRegistered<NeighborNested, NestedFieldMessage2::NestedMessageLevel1::NestedMessageLevel2*>(2, "qtprotobufnamespace::tests::nested::NestedFieldMessage2::NestedMessageLevel1::NestedMessageLevel2*", "neighborNested2");

    NestedFieldMessage::NestedMessage nested;
    nested.setTestFieldInt(15);
    NestedFieldMessage2::NestedMessageLevel1::NestedMessageLevel2 level2;
    level2.setTestFieldInt(20);

    NeighborNested test;
    test.setNeighborNested(nested);
    test.setNeighborNested2(level2);

    QCOMPARE(test.neighborNested().testFieldInt(), 15);
    QCOMPARE(test.neighborNested2().testFieldInt(), 20);

    const char *propertyName = "neighborNested";

    nested.setTestFieldInt(55);
    QVERIFY(test.setProperty(propertyName,
                             QVariant::fromValue<NestedFieldMessage::NestedMessage *>(
                                     new NestedFieldMessage::NestedMessage(nested))));
    QCOMPARE(*(test.property(propertyName).value<NestedFieldMessage::NestedMessage *>()), nested);
    QCOMPARE(test.neighborNested(), nested);

    propertyName = "neighborNested2";

    level2.setTestFieldInt(75);
    QVERIFY(test.setProperty(
            propertyName,
            QVariant::fromValue<NestedFieldMessage2::NestedMessageLevel1::NestedMessageLevel2 *>(
                    new NestedFieldMessage2::NestedMessageLevel1::NestedMessageLevel2(level2))));
    QCOMPARE(*(test.property(propertyName)
                       .value<NestedFieldMessage2::NestedMessageLevel1::NestedMessageLevel2 *>()),
             level2);
    QCOMPARE(test.neighborNested2(), level2);

    QCOMPARE(level2.propertyOrdering.getMessageFullName(),
             "qtprotobufnamespace.tests.nested.NestedFieldMessage2.NestedMessageLevel1."
             "NestedMessageLevel2");
}

void QtProtobufNestedTest::NestedNoFieldsTest()
{
    qProtobufAssertMessagePropertyRegistered<NestedNoFields::Nested, QtProtobuf::sint32>(1, "QtProtobuf::sint32", "testFieldInt");

    NestedNoFields::Nested test;
    test.setTestFieldInt(15);
    QCOMPARE(test.testFieldInt(), 15);

    const char *propertyName = "testFieldInt";

    QVERIFY(test.setProperty(propertyName, 55));
    QCOMPARE(test.property(propertyName).value<QtProtobuf::sint32>(), 55);
    QCOMPARE(test.testFieldInt(), 55);
}

void QtProtobufNestedTest::NestedCyclingTest()
{
    qProtobufAssertMessagePropertyRegistered<NestedCyclingA::NestedCyclingB, qtprotobufnamespace::tests::nested::NestedCyclingAA::NestedCyclingBB*>(1, "qtprotobufnamespace::tests::nested::NestedCyclingAA::NestedCyclingBB*", "testField");
    qProtobufAssertMessagePropertyRegistered<NestedCyclingAA::NestedCyclingBB, qtprotobufnamespace::tests::nested::NestedCyclingA::NestedCyclingB*>(1, "qtprotobufnamespace::tests::nested::NestedCyclingA::NestedCyclingB*", "testField");

    NestedCyclingA::NestedCyclingB test;
    NestedCyclingAA::NestedCyclingBB test2;
    test.setTestField(test2);
    test2.setTestField(test);
}

void QtProtobufNestedTest::UnusedNestedMessageTest()
{
    qProtobufAssertMessagePropertyRegistered<NestedFieldMessage::UnusedNestedMessage,
                                             QtProtobuf::sint32>(1, "QtProtobuf::sint32",
                                                                 "testFieldInt");
}

QTEST_MAIN(QtProtobufNestedTest)
#include "tst_protobuf_nestedtypes.moc"
