/**
 * Copyright (c) 2014-2026 Governikus GmbH & Co. KG, Germany
 */

#include "paos/retrieve/Transmit.h"

#include "Env.h"
#include "LogHandler.h"
#include "TestFileHelper.h"
#include "paos/retrieve/TransmitParser.h"

#include <QtCore>
#include <QtTest>

using namespace Qt::Literals::StringLiterals;
using namespace governikus;

class test_transmit
	: public QObject
{
	Q_OBJECT

	private Q_SLOTS:
		void initTestCase()
		{
			Env::getSingleton<LogHandler>()->init();
		}


		void cleanup()
		{
			Env::getSingleton<LogHandler>()->resetBacklog();
		}


		void parseXml()
		{
			QByteArray content = TestFileHelper::readFile(":/paos/Transmit.xml"_L1);
			QScopedPointer<Transmit> transmit(static_cast<Transmit*>(TransmitParser().parse(content)));
			QVERIFY(!transmit.isNull());
			auto inputApdusInfos = transmit->getInputApduInfos();

			QCOMPARE(transmit->getSlotHandle(), "34366364653038392D623031322D346664372D386233362D343664346232393537636236"_L1);
			QCOMPARE(inputApdusInfos.size(), 7);

			QCOMPARE(inputApdusInfos[0].getInputApdu(),
					QByteArray::fromHex("0CA4040C1D871101F31EC827ABAB92AABD958D297AF9CBD38E0891620AC1E4E686DD00"));
			QCOMPARE(inputApdusInfos[1].getInputApdu(),
					QByteArray::fromHex("8C2080001D871101F8699BC4D3460854255E0333183A22008E08F7F9BC3379E7B3FF00"));
			QCOMPARE(inputApdusInfos[2].getInputApdu(),
					QByteArray::fromHex("0C2241A41D8711016F4F279D5EA75DADCD5AB76A434593C08E0831D1B9B36C1504FB00"));
			QCOMPARE(inputApdusInfos[3].getInputApdu(),
					QByteArray::fromHex("0C8600000001428782013101F5441186D79BC429C472D4D0164862F62A92C6058B6D82F770A827765C9F04DF95F6080BEBC87997825A44921C0AC8FB18D322452C0146DC8565B42896E64DFB92708E732B3266B05BA5E4C0056332075B5CC1CCC4E273FA0DDF08E758027A4A337F54F9DBACBE73068376132641FB26D89DDE9625457000469705F33642318E7149C0636559FAC25B1F955C67390D2D47CBB98C36A8CC32260674A7F3F22A75DB976F364112B156B1E450DB000AA6A87A2D9338069D0012E8EBA3E60453E127D5427EBF3753C2A1BBAFFF8C2394FEB83064409F6412D9435A2C06EE016B26601F051073791C066B21D36ED8D5641C0456F69DFB1FA89CC100624C165B536F492AD2157DB89AA4902F04C57B70F0A97F88C92199216C4377AAB36E5793422582FAF181979F6ADB246584A6EF40CE66309701248E08B1FB40851AF2193E0000"));
			QCOMPARE(inputApdusInfos[4].getInputApdu(),
					QByteArray::fromHex("8C2080001D87110135B2C0DEDCEEF8399F9F0D7D0BD07D658E08FFB266818231747C00"));
			QCOMPARE(inputApdusInfos[5].getInputApdu(),
					QByteArray::fromHex("0C2241A41D8711010AF39947D7884D60639BA653B2DE18808E081F8D03FF36BB49AF00"));
			QCOMPARE(inputApdusInfos[6].getInputApdu(),
					QByteArray::fromHex("0C86000000014287820131014B102237A6D2AC0A7873562D14A36A98CEF053674C3CAB4F09FAFB09ED12941F0DDC27655679D4BD86A12FFD6A3F490B73F2DF03EF19C106D4519929A3116B7BD3AF9FE960BD88F301275EAD3FAA9E832BF93991728E378A2848D60596B1C643DA3E5ADBC119EB3EB444A3789367815B600D218C407A4016F8B3A7923EE8DC3CBE0BD8AA91763859E819B325479F605AA50FC8FF6066055678CE6C1A3FD1DB536E55C3A3D131367AD84B78213667F899D059D313CA7F1EC0785F20F4FEF14D1E3D077B620223E75F101B66262642B1D6416C44AA4ED2EFAC88D7E38EA4EE9EFAA3DAD71E70E96C696A137960532807B52C74070EDA3F573939B39725B86AD0A255E62D26A33C54154ADDF871ED06FD5038B38E3E5E42FF680807734385B900833F54350A447DF71F012B0BE59AB4C6F09701248E0826C663CDA8343CBD0000"));

			QCOMPARE(inputApdusInfos[0].getAcceptableStatusCodes(), QByteArrayList());
			QCOMPARE(inputApdusInfos[1].getAcceptableStatusCodes(), QByteArrayList());
			QCOMPARE(inputApdusInfos[2].getAcceptableStatusCodes(), QByteArrayList{"9000"});
			QCOMPARE(inputApdusInfos[3].getAcceptableStatusCodes(), QByteArrayList{"9001"});
			QCOMPARE(inputApdusInfos[4].getAcceptableStatusCodes(), QByteArrayList());
			QCOMPARE(inputApdusInfos[5].getAcceptableStatusCodes(), QByteArrayList{"9002"});
			QCOMPARE(inputApdusInfos[6].getAcceptableStatusCodes(), QByteArrayList{"9003"});
		}


		void parseXmlWithAddressing()
		{
			QByteArray content = TestFileHelper::readFile(":/paos/Transmit3.xml"_L1);
			QScopedPointer<Transmit> transmit(static_cast<Transmit*>(TransmitParser().parse(content)));
			QVERIFY(!transmit.isNull());
			auto inputApdusInfos = transmit->getInputApduInfos();

			QCOMPARE(transmit->getSlotHandle(), "34366364653038392D623031322D346664372D386233362D343664346232393537636236"_L1);
			QCOMPARE(transmit->getMessageId(), "urn:uuid:015c4aba-4b51-463d-95e4-df127c94a5ce"_L1);
			QCOMPARE(transmit->getRelatesTo(), "urn:uuid:04b2b166-77ad-42c9-bb7d-0c5e9798d337"_L1);
			QCOMPARE(inputApdusInfos.size(), 7);

			QCOMPARE(inputApdusInfos[0].getInputApdu(),
					QByteArray::fromHex("0CA4040C1D871101F31EC827ABAB92AABD958D297AF9CBD38E0891620AC1E4E686DD00"));
			QCOMPARE(inputApdusInfos[1].getInputApdu(),
					QByteArray::fromHex("8C2080001D871101F8699BC4D3460854255E0333183A22008E08F7F9BC3379E7B3FF00"));
			QCOMPARE(inputApdusInfos[2].getInputApdu(),
					QByteArray::fromHex("0C2241A41D8711016F4F279D5EA75DADCD5AB76A434593C08E0831D1B9B36C1504FB00"));
			QCOMPARE(inputApdusInfos[3].getInputApdu(),
					QByteArray::fromHex("0C8600000001428782013101F5441186D79BC429C472D4D0164862F62A92C6058B6D82F770A827765C9F04DF95F6080BEBC87997825A44921C0AC8FB18D322452C0146DC8565B42896E64DFB92708E732B3266B05BA5E4C0056332075B5CC1CCC4E273FA0DDF08E758027A4A337F54F9DBACBE73068376132641FB26D89DDE9625457000469705F33642318E7149C0636559FAC25B1F955C67390D2D47CBB98C36A8CC32260674A7F3F22A75DB976F364112B156B1E450DB000AA6A87A2D9338069D0012E8EBA3E60453E127D5427EBF3753C2A1BBAFFF8C2394FEB83064409F6412D9435A2C06EE016B26601F051073791C066B21D36ED8D5641C0456F69DFB1FA89CC100624C165B536F492AD2157DB89AA4902F04C57B70F0A97F88C92199216C4377AAB36E5793422582FAF181979F6ADB246584A6EF40CE66309701248E08B1FB40851AF2193E0000"));
			QCOMPARE(inputApdusInfos[4].getInputApdu(),
					QByteArray::fromHex("8C2080001D87110135B2C0DEDCEEF8399F9F0D7D0BD07D658E08FFB266818231747C00"));
			QCOMPARE(inputApdusInfos[5].getInputApdu(),
					QByteArray::fromHex("0C2241A41D8711010AF39947D7884D60639BA653B2DE18808E081F8D03FF36BB49AF00"));
			QCOMPARE(inputApdusInfos[6].getInputApdu(),
					QByteArray::fromHex("0C86000000014287820131014B102237A6D2AC0A7873562D14A36A98CEF053674C3CAB4F09FAFB09ED12941F0DDC27655679D4BD86A12FFD6A3F490B73F2DF03EF19C106D4519929A3116B7BD3AF9FE960BD88F301275EAD3FAA9E832BF93991728E378A2848D60596B1C643DA3E5ADBC119EB3EB444A3789367815B600D218C407A4016F8B3A7923EE8DC3CBE0BD8AA91763859E819B325479F605AA50FC8FF6066055678CE6C1A3FD1DB536E55C3A3D131367AD84B78213667F899D059D313CA7F1EC0785F20F4FEF14D1E3D077B620223E75F101B66262642B1D6416C44AA4ED2EFAC88D7E38EA4EE9EFAA3DAD71E70E96C696A137960532807B52C74070EDA3F573939B39725B86AD0A255E62D26A33C54154ADDF871ED06FD5038B38E3E5E42FF680807734385B900833F54350A447DF71F012B0BE59AB4C6F09701248E0826C663CDA8343CBD0000"));

			QCOMPARE(inputApdusInfos[0].getAcceptableStatusCodes(), QByteArrayList());
			QCOMPARE(inputApdusInfos[1].getAcceptableStatusCodes(), QByteArrayList());
			QCOMPARE(inputApdusInfos[2].getAcceptableStatusCodes(), QByteArrayList{"9000"});
			QCOMPARE(inputApdusInfos[3].getAcceptableStatusCodes(), QByteArrayList{"9001"});
			QCOMPARE(inputApdusInfos[4].getAcceptableStatusCodes(), QByteArrayList());
			QCOMPARE(inputApdusInfos[5].getAcceptableStatusCodes(), QByteArrayList{"9002"});
			QCOMPARE(inputApdusInfos[6].getAcceptableStatusCodes(), QByteArrayList{"9003"});
		}


		void parseAnswerAutent()
		{
			QByteArray content = TestFileHelper::readFile(":/paos/Transmit2.xml"_L1);
			QScopedPointer<Transmit> transmit(static_cast<Transmit*>(TransmitParser().parse(content)));
			QVERIFY(!transmit.isNull());
			auto inputApduInfos = transmit->getInputApduInfos();

			QCOMPARE(transmit->getSlotHandle(), "33393236303635313532"_L1);
			QCOMPARE(inputApduInfos.size(), 26);

			QByteArrayList expectedInputApdus;
			expectedInputApdus.append(QByteArray::fromHex("0CA4020C1D871101A59030685388957D6E2B5275AC82BB198E08870AED7F394826C000"));
			expectedInputApdus.append(QByteArray::fromHex("0CB0000000000E970200008E080388A41FBC277C680000"));
			expectedInputApdus.append(QByteArray::fromHex("0CA4020C1D8711013EFE77256902B3E2F1715FCA7EEF223A8E08A02C5F476D8E237700"));
			expectedInputApdus.append(QByteArray::fromHex("0CB0000000000E970200008E080AD2AA74759240CE0000"));
			expectedInputApdus.append(QByteArray::fromHex("0CA4020C1D8711014975FAC0882F0BF4C1E1C5CED555B1F58E08D11E50AA47C7CACC00"));
			expectedInputApdus.append(QByteArray::fromHex("0CB0000000000E970200008E08F98D94F3906A49170000"));
			expectedInputApdus.append(QByteArray::fromHex("0CA4020C1D871101C29B19471B3E36927EC6DA64AEF864CD8E08247F32860E4568A600"));
			expectedInputApdus.append(QByteArray::fromHex("0CB0000000000E970200008E08C5C819FB6A0D695E0000"));
			expectedInputApdus.append(QByteArray::fromHex("0CA4020C1D8711018F820CDBAD555652034E626FB37F86138E08CD3315A36561145000"));
			expectedInputApdus.append(QByteArray::fromHex("0CB0000000000E970200008E08DA60F404B079B0420000"));
			expectedInputApdus.append(QByteArray::fromHex("0CA4020C1D8711018540F01B03C3E973C5777D9BB1F04E9E8E08286A94789231A2FC00"));
			expectedInputApdus.append(QByteArray::fromHex("0CB0000000000E970200008E086A0FDF4AD3FC272B0000"));
			expectedInputApdus.append(QByteArray::fromHex("0CA4020C1D87110195BCF8D7ACEA42AD4683947DBE73BE078E0810B17C642A9001BC00"));
			expectedInputApdus.append(QByteArray::fromHex("0CB0000000000E970200008E08DE56082154DF14190000"));
			expectedInputApdus.append(QByteArray::fromHex("0CA4020C1D871101C2C66976E0156AED1CF30DA2310C6A708E088F9C219BC772629100"));
			expectedInputApdus.append(QByteArray::fromHex("0CB0000000000E970200008E080556C2D7E030B48E0000"));
			expectedInputApdus.append(QByteArray::fromHex("0CA4020C1D87110160A2B6BA12D2EE2171251C30FBC039518E085AAC7E6E9DDD37B600"));
			expectedInputApdus.append(QByteArray::fromHex("0CB0000000000E970200008E08F74B2B26F0CDCCE90000"));
			expectedInputApdus.append(QByteArray::fromHex("0CA4020C1D8711014C3A0C102647A46613A18E3D5480C1328E08D4A2D7785C00692E00"));
			expectedInputApdus.append(QByteArray::fromHex("0CB0000000000E970200008E080C2D48357F0D592D0000"));
			expectedInputApdus.append(QByteArray::fromHex("0CA4020C1D8711017EFE5C0C79DE36B538DDF1FFBF25F1488E08680FA5060E8CCD8A00"));
			expectedInputApdus.append(QByteArray::fromHex("0CB0000000000E970200008E08D871CCADC9A53AA40000"));
			expectedInputApdus.append(QByteArray::fromHex("0CA4020C1D87110137B3389C11D89860CD4CEF705249C38C8E08BE08E0801F8C1E2700"));
			expectedInputApdus.append(QByteArray::fromHex("0CB0000000000E970200008E0867726A6E5F4F8E370000"));
			expectedInputApdus.append(QByteArray::fromHex("0CA4020C1D871101B07423F80083EDD818123BF8422ED77C8E089508DEF13CBE6D8600"));
			expectedInputApdus.append(QByteArray::fromHex("0CB0000000000E970200008E0800A7E854CC4A6F780000"));
			QCOMPARE(expectedInputApdus.size(), 26);

			for (int i = 0; i < 26; ++i)
			{
				QCOMPARE(inputApduInfos[i].getInputApdu(), expectedInputApdus[i]);
				QCOMPARE(inputApduInfos[i].getAcceptableStatusCodes(), QByteArrayList());
			}
		}


		void checkUniqueEntries_data()
		{
			QTest::addColumn<QByteArray>("replaceIdentifier");
			QTest::addColumn<QByteArray>("replaceContent");

			QTest::newRow("InputAPDU") << QByteArray("<!-- INPUTAPDU -->") << QByteArray("34366364653038392D623031322D346664372D386233362D343664346232393537636236");
			QTest::newRow("SlotHandle") << QByteArray("<!-- SLOTHANDLE -->") << QByteArray("0CA4040C1D871101F31EC827ABAB92AABD958D297AF9CBD38E0891620AC1E4E686DD00");
		}


		void checkUniqueEntries()
		{
			QFETCH(QByteArray, replaceIdentifier);
			QFETCH(QByteArray, replaceContent);

			const QByteArray tag = QByteArray(QTest::currentDataTag());
			const QByteArray data = '<' + tag + '>' + replaceContent + "</" + tag + '>';

			QByteArray content = TestFileHelper::readFile(":/paos/Transmit_template.xml"_L1);
			content = content.replace(replaceIdentifier, data + data);

			QScopedPointer<Transmit> transmit(static_cast<Transmit*>(TransmitParser().parse(content)));
			QVERIFY(transmit.isNull());

			const QByteArray duplicateUniqueElement = "Duplicate unique element: \"" + tag + "\"";
			QVERIFY(Env::getSingleton<LogHandler>()->getBacklog().contains(duplicateUniqueElement));
		}


};

QTEST_GUILESS_MAIN(test_transmit)
#include "test_transmit.moc"
