/*
 * Copyright (C) 2014-2021 CZ.NIC
 *
 * 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
 * (at your option) 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/>.
 *
 * In addition, as a special exception, the copyright holders give
 * permission to link the code of portions of this program with the
 * OpenSSL library under certain conditions as described in each
 * individual source file, and distribute linked combinations including
 * the two.
 */

#include <QByteArray>
#include <QDateTime>
#include <QFile>
#include <QString>
#include <QtTest/QtTest>
#include <QObject>

#include "src/datovka_shared/log/log.h"
#include "src/datovka_shared/records_management/json/upload_account_status.h"
#include "src/datovka_shared/records_management/json/upload_hierarchy.h"
#include "src/global.h"
#include "src/records_management/content/automatic_upload_target.h"
#include "tests/test_records_management.h"

class TestRecordsManagement : public QObject {
	Q_OBJECT

public:
	TestRecordsManagement(void);

private slots:
	void initTestCase(void);

	void cleanupTestCase(void);

	void TestUploadAccountStatusReq(void);

	void TestAutomaticUploadTarget(void);
};

TestRecordsManagement::TestRecordsManagement(void)
{
}

void TestRecordsManagement::initTestCase(void)
{
	QVERIFY(GlobInstcs::logPtr == Q_NULLPTR);
	GlobInstcs::logPtr = new (::std::nothrow) LogDevice;
	QVERIFY(GlobInstcs::logPtr != Q_NULLPTR);
}

void TestRecordsManagement::cleanupTestCase(void)
{
	delete GlobInstcs::logPtr; GlobInstcs::logPtr = Q_NULLPTR;
}

static
QDateTime currentTimeWithoutMsec(void)
{
	QDateTime dateTime = QDateTime::currentDateTime();
	QTime time = dateTime.time();
	if (time.msec() > 0) {
		/* Subtract the milliseconds. */
		time = time.addMSecs(- time.msec());
		dateTime.setTime(time);
	}
	return dateTime;
}

void TestRecordsManagement::TestUploadAccountStatusReq(void)
{
	const QString strBoxId("boxId");
	const QString strUserId("userId");
	const QDateTime time = currentTimeWithoutMsec();
	const int rcvdNotAccepted = 10;
	const int sntNotAccepted = 15;
	const int rcvdUntracked = 20;
	const int sntUntracked = 25;
	const QString strUserAccountName("userAccountName");

	{
		RecMgmt::UploadAccountStatusReq uasr(
		    QString(), QString(), QDateTime(), -1, -1, -1, -1,
		    QString());
		QVERIFY(!uasr.isValid());
		QVERIFY(uasr.boxId() == QString());
		QVERIFY(uasr.userId() == QString());
		QVERIFY(uasr.time() == QDateTime());
		QVERIFY(uasr.rcvdNotAccepted() == -1);
		QVERIFY(uasr.sntNotAccepted() == -1);
		QVERIFY(uasr.rcvdNotInRegMgmt() == -1);
		QVERIFY(uasr.sntNotInRegMgmt() == -1);
		QVERIFY(uasr.userAccountName() == QString());
	}

	{
		RecMgmt::UploadAccountStatusReq uasr(
		    QString(), strUserId, time,
		    rcvdNotAccepted, sntNotAccepted,
		    rcvdUntracked, sntUntracked, strUserAccountName);
		QVERIFY(!uasr.isValid());
		QVERIFY(uasr.boxId() == QString());
		QVERIFY(uasr.userId() == strUserId);
		QVERIFY(uasr.time() == time);
		QVERIFY(uasr.rcvdNotAccepted() == rcvdNotAccepted);
		QVERIFY(uasr.sntNotAccepted() == sntNotAccepted);
		QVERIFY(uasr.rcvdNotInRegMgmt() == rcvdUntracked);
		QVERIFY(uasr.sntNotInRegMgmt() == sntUntracked);
		QVERIFY(uasr.userAccountName() == strUserAccountName);
	}

	{
		RecMgmt::UploadAccountStatusReq uasr(
		    strBoxId, QString(), time,
		    rcvdNotAccepted, sntNotAccepted,
		    rcvdUntracked, sntUntracked, strUserAccountName);
		QVERIFY(!uasr.isValid());
		QVERIFY(uasr.boxId() == strBoxId);
		QVERIFY(uasr.userId() == QString());
		QVERIFY(uasr.time() == time);
		QVERIFY(uasr.rcvdNotAccepted() == rcvdNotAccepted);
		QVERIFY(uasr.sntNotAccepted() == sntNotAccepted);
		QVERIFY(uasr.rcvdNotInRegMgmt() == rcvdUntracked);
		QVERIFY(uasr.sntNotInRegMgmt() == sntUntracked);
		QVERIFY(uasr.userAccountName() == strUserAccountName);
	}

	{
		RecMgmt::UploadAccountStatusReq uasr(
		    strBoxId, strUserId, QDateTime(),
		    rcvdNotAccepted, sntNotAccepted,
		    rcvdUntracked, sntUntracked, strUserAccountName);
		QVERIFY(!uasr.isValid());
		QVERIFY(uasr.boxId() == strBoxId);
		QVERIFY(uasr.userId() == strUserId);
		QVERIFY(uasr.time() == QDateTime());
		QVERIFY(uasr.rcvdNotAccepted() == rcvdNotAccepted);
		QVERIFY(uasr.sntNotAccepted() == sntNotAccepted);
		QVERIFY(uasr.rcvdNotInRegMgmt() == rcvdUntracked);
		QVERIFY(uasr.sntNotInRegMgmt() == sntUntracked);
		QVERIFY(uasr.userAccountName() == strUserAccountName);
	}

	{
		RecMgmt::UploadAccountStatusReq uasr(
		    strBoxId, strUserId, time,
		    -1, sntNotAccepted,
		    rcvdUntracked, sntUntracked, strUserAccountName);
		QVERIFY(!uasr.isValid());
		QVERIFY(uasr.boxId() == strBoxId);
		QVERIFY(uasr.userId() == strUserId);
		QVERIFY(uasr.time() == time);
		QVERIFY(uasr.rcvdNotAccepted() == -1);
		QVERIFY(uasr.sntNotAccepted() == sntNotAccepted);
		QVERIFY(uasr.rcvdNotInRegMgmt() == rcvdUntracked);
		QVERIFY(uasr.sntNotInRegMgmt() == sntUntracked);
		QVERIFY(uasr.userAccountName() == strUserAccountName);
	}

	{
		RecMgmt::UploadAccountStatusReq uasr(
		    strBoxId, strUserId, time,
		    rcvdNotAccepted, -1,
		    rcvdUntracked, sntUntracked, strUserAccountName);
		QVERIFY(!uasr.isValid());
		QVERIFY(uasr.boxId() == strBoxId);
		QVERIFY(uasr.userId() == strUserId);
		QVERIFY(uasr.time() == time);
		QVERIFY(uasr.rcvdNotAccepted() == rcvdNotAccepted);
		QVERIFY(uasr.sntNotAccepted() == -1);
		QVERIFY(uasr.rcvdNotInRegMgmt() == rcvdUntracked);
		QVERIFY(uasr.sntNotInRegMgmt() == sntUntracked);
		QVERIFY(uasr.userAccountName() == strUserAccountName);
	}

	{
		RecMgmt::UploadAccountStatusReq uasr(
		    strBoxId, strUserId, time,
		    rcvdNotAccepted, sntNotAccepted,
		    -1, sntUntracked, strUserAccountName);
		QVERIFY(!uasr.isValid());
		QVERIFY(uasr.boxId() == strBoxId);
		QVERIFY(uasr.userId() == strUserId);
		QVERIFY(uasr.time() == time);
		QVERIFY(uasr.rcvdNotAccepted() == rcvdNotAccepted);
		QVERIFY(uasr.sntNotAccepted() == sntNotAccepted);
		QVERIFY(uasr.rcvdNotInRegMgmt() == -1);
		QVERIFY(uasr.sntNotInRegMgmt() == sntUntracked);
		QVERIFY(uasr.userAccountName() == strUserAccountName);
	}

	{
		RecMgmt::UploadAccountStatusReq uasr(
		    strBoxId, strUserId, time,
		    rcvdNotAccepted, sntNotAccepted,
		    rcvdUntracked, -1, strUserAccountName);
		QVERIFY(!uasr.isValid());
		QVERIFY(uasr.boxId() == strBoxId);
		QVERIFY(uasr.userId() == strUserId);
		QVERIFY(uasr.time() == time);
		QVERIFY(uasr.rcvdNotAccepted() == rcvdNotAccepted);
		QVERIFY(uasr.sntNotAccepted() == sntNotAccepted);
		QVERIFY(uasr.rcvdNotInRegMgmt() == rcvdUntracked);
		QVERIFY(uasr.sntNotInRegMgmt() == -1);
		QVERIFY(uasr.userAccountName() == strUserAccountName);
	}

	{
		RecMgmt::UploadAccountStatusReq uasr(
		    strBoxId, strUserId, time,
		    rcvdNotAccepted, sntNotAccepted,
		    rcvdUntracked, sntUntracked, QString());
		QVERIFY(uasr.isValid());
		QVERIFY(uasr.boxId() == strBoxId);
		QVERIFY(uasr.userId() == strUserId);
		QVERIFY(uasr.time() == time);
		QVERIFY(uasr.rcvdNotAccepted() == rcvdNotAccepted);
		QVERIFY(uasr.sntNotAccepted() == sntNotAccepted);
		QVERIFY(uasr.rcvdNotInRegMgmt() == rcvdUntracked);
		QVERIFY(uasr.sntNotInRegMgmt() == sntUntracked);
		QVERIFY(uasr.userAccountName() == QString());
	}

	RecMgmt::UploadAccountStatusReq uasr0(
	    strBoxId, strUserId, time,
	    rcvdNotAccepted, sntNotAccepted, rcvdUntracked, sntUntracked,
	    strUserAccountName);
	QVERIFY(uasr0.isValid());
	QVERIFY(uasr0.boxId() == strBoxId);
	QVERIFY(uasr0.userId() == strUserId);
	QVERIFY(uasr0.time() == time);
	QVERIFY(uasr0.rcvdNotAccepted() == rcvdNotAccepted);
	QVERIFY(uasr0.sntNotAccepted() == sntNotAccepted);
	QVERIFY(uasr0.rcvdNotInRegMgmt() == rcvdUntracked);
	QVERIFY(uasr0.sntNotInRegMgmt() == sntUntracked);
	QVERIFY(uasr0.userAccountName() == strUserAccountName);

	QByteArray jsonData = uasr0.toJson();
	QVERIFY(!jsonData.isEmpty());

	{
		bool ok = false;
		RecMgmt::UploadAccountStatusReq uasr =
		    RecMgmt::UploadAccountStatusReq::fromJson(QByteArray(), &ok);
		QVERIFY(ok == false);
		QVERIFY(!uasr.isValid());
	}

	bool ok = false;
	RecMgmt::UploadAccountStatusReq uasr1 =
	    RecMgmt::UploadAccountStatusReq::fromJson(jsonData, &ok);
	QVERIFY(ok == true);
	QVERIFY(uasr1.isValid());
	QVERIFY(uasr1.boxId() == uasr0.boxId());
	QVERIFY(uasr1.userId() == uasr0.userId());
	QVERIFY(uasr1.time() == uasr0.time());
	QVERIFY(uasr1.rcvdNotAccepted() == uasr0.rcvdNotAccepted());
	QVERIFY(uasr1.sntNotAccepted() == uasr0.sntNotAccepted());
	QVERIFY(uasr1.rcvdNotInRegMgmt() == uasr0.rcvdNotInRegMgmt());
	QVERIFY(uasr1.sntNotInRegMgmt() == uasr0.sntNotInRegMgmt());
	QVERIFY(uasr1.userAccountName() == uasr0.userAccountName());
}

/*!
 * @breaf Read whole file content.
 *
 * @param[in] fileName File path.
 */
static
QByteArray readFileData(const QString &fileName)
{
	if (Q_UNLIKELY(fileName.isEmpty())) {
		return QByteArray();
	}

	QFile file(fileName);
	if (!file.exists() || !file.open(QIODevice::ReadOnly)) {
		return QByteArray();
	}

	QByteArray data = file.readAll();
	file.close();

	return data;
}

void TestRecordsManagement::TestAutomaticUploadTarget(void)
{
	RecMgmt::AutomaticUploadTarget aut;
	{
		QByteArray json = readFileData(
		    "data/records_management_upload_hierarchy_reply.json");
		QVERIFY(!json.isEmpty());

		RecMgmt::UploadHierarchyResp uhr =
		    RecMgmt::UploadHierarchyResp::fromJson(json);
		QVERIFY(uhr.isValid());

		aut = RecMgmt::AutomaticUploadTarget::getUnambiguousTargets(uhr);
		QVERIFY(!aut.isNull());
	}

	QVERIFY(!aut.haveCaseId(QString()));
	QVERIFY(!aut.haveCaseId(""));
	QVERIFY(aut.haveCaseId("SC-0001"));
	QVERIFY(!aut.haveCaseId("SC-0002"));

	QVERIFY(!aut.haveAmbiguousCaseId(QString()));
	QVERIFY(!aut.haveAmbiguousCaseId(""));
	QVERIFY(!aut.haveAmbiguousCaseId("SC-0001"));
	QVERIFY(aut.haveAmbiguousCaseId("SC-0002"));

	QVERIFY(!aut.haveCourtCaseId(QString()));
	QVERIFY(!aut.haveCourtCaseId(""));
	QVERIFY(!aut.haveCourtCaseId("2020"));
	QVERIFY(aut.haveCourtCaseId("2021"));

	QVERIFY(!aut.haveAmbiguousCourtCaseId(QString()));
	QVERIFY(!aut.haveAmbiguousCourtCaseId(""));
	QVERIFY(aut.haveAmbiguousCourtCaseId("2020"));
	QVERIFY(!aut.haveAmbiguousCourtCaseId("2021"));
}

QObject *newTestRecordsManagement(void)
{
	return new (::std::nothrow) TestRecordsManagement();
}

//QTEST_MAIN(TestRecordsManagement)
#include "test_records_management.moc"
