/*******************************************************************************
***  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 <pecunia/Codes.h>
using pecunia::currency::Iso4217Codes;
#include <pecunia/Money.h>
using pecunia::currency::Money;
#include <QDate>
using ::QDate;
#include <QObject>
using ::QObject;
// using Q_OBJECT
#include <QSignalSpy>
using ::QSignalSpy;
#include <QTest>
// using QTEST_MAIN
#include <qt-mocks/Matchers.h>
using qt_mocks::equals;
// using QVERIFY_FALSE
// using QVERIFY_THAT
// using QVERIFY_TRUE

#include <chrono>
using std::chrono::hours;
#include <set>
using std::set;

#include <accounting/AccountCode.h>
using drn::accounting::AccountCode;
using drn::accounting::AccountNumber;
#include <banking/BankName.h>
using drn::banking::BankName;
#include <banking/BankAccount.h>
using drn::banking::BankAccount;
#include <banking/BankAccountType.h>
using drn::banking::BankAccountType;
using drn::banking::SupportedAccountTypes;
#include <budgeting/BudgetSource.h>
using drn::budgeting::BudgetSource;
#include <budgeting/EventFrequency.h>
using drn::budgeting::EventFrequency;
#include <budgeting/Goal.h>
using drn::budgeting::Goal;
#include <foundation/CalendarTime.hpp>
using drn::foundation::Days;
#include <foundation/ObserverPtr.hpp>
using drn::foundation::ObserverPtr;
#include <foundation/Optional.hpp>
using drn::foundation::Optional;
#include <foundation/PresentationText.h>
using drn::foundation::presentationText;
#include <internal/GoalEntryWidget.h>
using drn::desktop_ui::internal::GoalEntryWidget;


namespace drn
{
namespace desktop_ui
{
namespace internal
{
namespace tests
{

struct GoalEntryWidgetUT : QObject
{
	Q_OBJECT

	const Goal computer_{
		BudgetSource{"Computer"},
		Money{150u, 2000u, Iso4217Codes::USD},
		EventFrequency::Monthly,
		QDate::currentDate().addDays(5),
		Money{15000u, 2000u, Iso4217Codes::USD}
	};
	const set<Iso4217Codes> usableCurrencies_{
		{
			Iso4217Codes::PLN,
			Iso4217Codes::EUR,
			Iso4217Codes::USD
		}
	};
	const BankName homeFederal_{"Home Federal"};
	const BankName c1st_{"Community 1st"};
	const set<BankName> banks_{
		{
			this->homeFederal_,
			this->c1st_
		}
	};
	const AccountCode computerCode_{AccountNumber{2004u}, this->computer_.source().name()};
	const Optional<BankAccount> bankAccount_{
		BankAccount{
			this->homeFederal_,
			BankAccountType{this->computerCode_, SupportedAccountTypes::Savings}
		}
	};
	const Money totalWage_{5000, 0u, Iso4217Codes::USD};
	const hours hrInWeek_{40};
	const Days dayInWeek_{5};

private slots:
	//{ constructor Tests

	void constructor_fullInitWithoutGoalWithoutAccount_ShouldBeValues()
	{
		const GoalEntryWidget widget{
			{},
			{},
			this->banks_,
			this->totalWage_,
			this->hrInWeek_,
			this->dayInWeek_,
			this->usableCurrencies_,
			nullptr
		};
		QVERIFY_FALSE(widget.originalSource().hasValue());
		QVERIFY_THAT(widget.banks(), equals(this->banks_));
		QVERIFY_THAT(widget.finalAmount->currencies(), equals(this->usableCurrencies_));
		QVERIFY_THAT(widget.periodAmount->currencies(), equals(this->usableCurrencies_));
		QVERIFY_THAT(widget.source(), equals(BudgetSource{}));
		QVERIFY_THAT(widget.final(), equals(Money{}));
		QVERIFY_THAT(widget.period(), equals(EventFrequency::Unknown));
		QVERIFY_THAT(widget.amount(), equals(Money{}));
		QVERIFY_THAT(widget.nextOccurOn(), equals(QDate::currentDate()));
		QVERIFY_FALSE(widget.bank().hasValue());
		QVERIFY_FALSE(widget.account().hasValue());
		QVERIFY_FALSE(widget.bankAccountType().hasValue());
		QVERIFY_FALSE(widget.shouldRemove());
		QVERIFY_FALSE(widget.isDirty());
	}

	void constructor_fullInitWithGoalWithoutAccount_ShouldBeValues()
	{
		const GoalEntryWidget widget{
			this->computer_,
			{},
			this->banks_,
			this->totalWage_,
			this->hrInWeek_,
			this->dayInWeek_,
			this->usableCurrencies_,
			nullptr
		};
		QVERIFY_THAT(widget.originalSource().valueOrDefault(), equals(this->computer_.source()));
		QVERIFY_THAT(widget.banks(), equals(this->banks_));
		QVERIFY_THAT(widget.finalAmount->currencies(), equals(this->usableCurrencies_));
		QVERIFY_THAT(widget.periodAmount->currencies(), equals(this->usableCurrencies_));
		QVERIFY_THAT(widget.source(), equals(this->computer_.source()));
		QVERIFY_THAT(widget.final(), equals(this->computer_.final()));
		QVERIFY_THAT(widget.period(), equals(this->computer_.period()));
		QVERIFY_THAT(widget.amount(), equals(this->computer_.amount()));
		QVERIFY_THAT(widget.nextOccurOn(), equals(this->computer_.nextOccurOn()));
		QVERIFY_FALSE(widget.bank().hasValue());
		QVERIFY_FALSE(widget.account().hasValue());
		QVERIFY_FALSE(widget.bankAccountType().hasValue());
		QVERIFY_FALSE(widget.shouldRemove());
		QVERIFY_FALSE(widget.isDirty());
	}

	void constructor_fullInitWithGoalWithAccount_ShouldBeValues()
	{
		const GoalEntryWidget widget{
			this->computer_,
			this->bankAccount_,
			this->banks_,
			this->totalWage_,
			this->hrInWeek_,
			this->dayInWeek_,
			this->usableCurrencies_,
			nullptr
		};
		QVERIFY_THAT(widget.originalSource().valueOrDefault(), equals(this->computer_.source()));
		QVERIFY_THAT(widget.banks(), equals(this->banks_));
		QVERIFY_THAT(widget.finalAmount->currencies(), equals(this->usableCurrencies_));
		QVERIFY_THAT(widget.periodAmount->currencies(), equals(this->usableCurrencies_));
		QVERIFY_THAT(widget.source(), equals(this->computer_.source()));
		QVERIFY_THAT(widget.final(), equals(this->computer_.final()));
		QVERIFY_THAT(widget.period(), equals(this->computer_.period()));
		QVERIFY_THAT(widget.amount(), equals(this->computer_.amount()));
		QVERIFY_THAT(widget.nextOccurOn(), equals(this->computer_.nextOccurOn()));
		QVERIFY_THAT(widget.bank().valueOrDefault(), equals(this->bankAccount_->bank_));
		QVERIFY_THAT(
			widget.storedInCmbbx->accountCode().valueOrDefault(),
			equals(this->bankAccount_->account_.code_)
		);
		QVERIFY_THAT(
			widget.account().valueOrDefault(),
			equals(this->bankAccount_->account_.code_)
		);
		QVERIFY_THAT(
			widget.bankAccountType().valueOrDefault(),
			equals(this->bankAccount_->account_.type_)
		);
		QVERIFY_FALSE(widget.shouldRemove());
		QVERIFY_FALSE(widget.isDirty());
	}

	//}
};


}}}}

QTEST_MAIN(drn::desktop_ui::internal::tests::GoalEntryWidgetUT)
#include "GoalEntryWidget-unit-tests.moc"
