/*******************************************************************************
***  This file is part of Dux Rei Nummariae.                                 ***
***                                                                          ***
***  Copyright (C) 2017, 2018, 2019, 2020, 2021                              ***
***  John Schneiderman <Licensing _AT_ Schneiderman _DOT_ me>                ***
***                                                                          ***
***  This program is free software: you can redistribute it and/or modify it ***
***  under the terms of the GNU Affero 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 Affero General Public License for more details.             ***
***                                                                          ***
***  You should have received a copy of the GNU Affero General Public License***
***  along with this program. If not, see <http://www.gnu.org/licenses/>.    ***
*******************************************************************************/
#include <QBuffer>
using ::QBuffer;
#include <QByteArray>
using ::QByteArray;
#include <QTest>
// using QCOMPARE.
// using QTEST_MAIN.
#include <qt-mocks/Matchers.h>
using qt_mocks::equals;
// using QVERIFY_THAT;

#include <map>
using std::map;
#include <tuple>
using std::get;

#include <accounting/AccountCode.h>
using drn::accounting::AccountCode;
using drn::accounting::AccountNumber;
#include <accounting/LedgerBooks.h>
using drn::accounting::GeneralLedger;
#include <banking/Bank.h>
using drn::banking::Bank;
#include <banking/BankAccountType.h>
using drn::banking::SupportedAccountTypes;
#include <banking/BankMap.h>
using drn::banking::BankMap;
#include <banking/BankName.h>
using drn::banking::BankName;
#include "BudgetFileContents.h"
using drn::file_storage::tests::validSupportedAccountTypes;
using drn::file_storage::tests::validBanks;
using drn::file_storage::tests::validBudget;
using drn::file_storage::tests::validBudgetCodes;
using drn::file_storage::tests::validBudgetOpeningAccountNoTransactions;
using drn::file_storage::tests::validContents;
using drn::file_storage::tests::validEmptyContents;
using drn::file_storage::tests::validGeneralLedger;
using drn::file_storage::tests::validGeneralLedgerOpeningAccountNoTransactions;
using drn::file_storage::tests::validOpeningAccountNoTransactionsContents;
#include <budgeting/Budget.h>
using drn::budgeting::Budget;
#include <budgeting/BudgetSource.h>
using drn::budgeting::BudgetSource;
#include <foundation/TypeIndexMap.hpp>
using drn::foundation::TypeIndexMap;
#include <internal/XmlBudgetFile.h>
using drn::file_storage::internal::read;
using drn::file_storage::internal::write;


namespace drn
{
namespace file_storage
{
namespace internal
{
namespace tests
{

struct XmlBudgetFileUT : QObject
{
	Q_OBJECT

private slots:
	//{ read XML File

	void read_FileValid_ShouldSucceed()
	{
		QByteArray budgetFileContents{validContents()};
		QBuffer file{&budgetFileContents};
		file.open(QFile::ReadOnly | QFile::Text);
		const auto parsed{read(file)};
		const Budget expectedBudget{validBudget()};
		const GeneralLedger expectedGeneralLedger{validGeneralLedger()};
		const BankMap expectedBanks{validBanks()};
		const auto expectedSupportedAccountTypes{validSupportedAccountTypes()};
		const auto expectedBudgetCodes{validBudgetCodes()};
		QVERIFY_THAT(get<0>(parsed), equals(expectedGeneralLedger));
		QVERIFY_THAT(get<1>(parsed), equals(expectedBudget));
		QVERIFY_THAT(get<2>(parsed), equals(expectedBudgetCodes));
		QVERIFY_THAT(get<3>(parsed), equals(expectedBanks));
		QVERIFY_THAT(get<4>(parsed), equals(expectedSupportedAccountTypes));
	}

	void read_BudgetEmpty_ShouldSucceed()
	{
		QByteArray budgetFileContents{validEmptyContents()};
		QBuffer file{&budgetFileContents};
		file.open(QFile::ReadOnly | QFile::Text);
		const auto parsed{read(file)};
		const Budget expectedBudget{};
		const GeneralLedger expectedGeneralLedger{};
		const BankMap expectedBanks{};
		const map<BankName, map<AccountNumber, SupportedAccountTypes>> expectedSupportedAccountTypes{};
		const TypeIndexMap<BudgetSource, AccountCode> expectedBudgetCodes{};
		QCOMPARE(get<0>(parsed), expectedGeneralLedger);
		QCOMPARE(get<1>(parsed), expectedBudget);
		QVERIFY_THAT(get<2>(parsed), equals(expectedBudgetCodes));
		QVERIFY_THAT(get<3>(parsed), equals(expectedBanks));
		QVERIFY_THAT(get<4>(parsed), equals(expectedSupportedAccountTypes));
	}

	void read_FileValidNoOpeningAccount_ShouldSucceed()
	{
		QByteArray budgetFileContents{validOpeningAccountNoTransactionsContents()};
		QBuffer file{&budgetFileContents};
		file.open(QFile::ReadOnly | QFile::Text);
		const auto parsed{read(file)};
		const Budget expectedBudget{validBudgetOpeningAccountNoTransactions()};
		const GeneralLedger expectedGeneralLedger{validGeneralLedgerOpeningAccountNoTransactions()};
		const BankMap expectedBanks{};
		const map<BankName, map<AccountNumber, SupportedAccountTypes>> expectedSupportedAccountTypes{};
		QCOMPARE(get<0>(parsed), expectedGeneralLedger);
		QCOMPARE(get<1>(parsed), expectedBudget);
		QVERIFY_TRUE(get<2>(parsed).empty());
		QVERIFY_THAT(get<3>(parsed), equals(expectedBanks));
		QVERIFY_THAT(get<4>(parsed), equals(expectedSupportedAccountTypes));
	}

	//}

	//{ write XML File

	void write_BudgetValid_ShouldSucceed()
	{
		QByteArray budgetFileContents{};
		QBuffer file{&budgetFileContents};
		file.open(QFile::WriteOnly | QFile::Text);
		write(
			validBudget(),
			validGeneralLedger(),
			validBanks(),
			validSupportedAccountTypes(),
			validBudgetCodes(),
			file,
			true
		);
		const std::string actual{budgetFileContents.constData()};
		const std::string expected{validContents()};
		QVERIFY_THAT(actual, equals(expected));
	}

	void write_BudgetEmpty_ShouldSucceed()
	{
		QByteArray budgetFileContents{};
		QBuffer file{&budgetFileContents};
		file.open(QFile::WriteOnly | QFile::Text);
		write({}, {}, {}, {}, {}, file, true);
		QCOMPARE(budgetFileContents.constData(), validEmptyContents());
	}


	void write_FileValidNoOpeningAccount_ShouldSucceed()
	{
		QByteArray budgetFileContents{};
		QBuffer file{&budgetFileContents};
		file.open(QFile::WriteOnly | QFile::Text);
		write(
			validBudgetOpeningAccountNoTransactions(),
			validGeneralLedgerOpeningAccountNoTransactions(),
			{},
			{},
			{},
			file,
			true
		);
		QCOMPARE(budgetFileContents.constData(), validOpeningAccountNoTransactionsContents());
	}

	//}
};

}}}}

QTEST_MAIN(drn::file_storage::internal::tests::XmlBudgetFileUT)
#include "XmlBudgetFile-unit-tests.moc"
