/*******************************************************************************
***  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 "BudgetFileContents.h"
using std::map;

#include <pecunia/Codes.h>
using pecunia::currency::Iso4217Codes;
#include <pecunia/Money.h>
using pecunia::currency::Money;
#include <QDate>
using ::QDate;
#include <QFileInfo>
using ::QFileInfo;
#include <QString>
using ::QString;

#include <string>
using namespace std::string_literals;
#include <set>
using std::set;

#include <accounting/Account.h>
using drn::accounting::Account;
using drn::accounting::AccountTypes;
#include <accounting/AccountCode.h>
using drn::accounting::AccountCode;
using drn::accounting::AccountNumber;
#include <accounting/LedgerBooks.h>
using drn::accounting::GeneralLedger;
using drn::accounting::LedgerAccount;
#include <accounting/Transaction.h>
using drn::accounting::Transaction;
using drn::accounting::TransactionNumber;
using drn::accounting::TransactionStatuses;
#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 <budgeting/Budget.h>
using drn::budgeting::Budget;
#include <budgeting/BudgetSource.h>
using drn::budgeting::BudgetSource;
#include <budgeting/Nontrack.h>
using drn::budgeting::Nontrack;
#include <budgeting/EventFrequency.h>
using drn::budgeting::EventFrequency;
#include <budgeting/Bill.h>
using drn::budgeting::Bill;
#include <budgeting/BillMap.hpp>
using drn::budgeting::BillMap;
#include <budgeting/Goal.h>
using drn::budgeting::Goal;
#include <budgeting/GoalMap.h>
using drn::budgeting::GoalMap;
#include <budgeting/Wage.h>
using drn::budgeting::Wage;
#include <budgeting/WageMap.hpp>
using drn::budgeting::WageMap;
#include <budgeting/Debt.h>
using drn::budgeting::Debt;
using drn::budgeting::Percentage;
#include <budgeting/DebtMap.h>
using drn::budgeting::DebtMap;
#include <foundation/TypeIndexMap.hpp>
using drn::foundation::TypeIndexMap;


QString drn::file_storage::tests::unitTestDirectoryPath()
{
	return QFileInfo{__FILE__}.absolutePath();
}

// N.B. This is expected to be in step with validBudget.
const char* drn::file_storage::tests::validContents()
{
	constexpr auto budgetContents{R"~(<?xml version="1.0" encoding="UTF-8"?>
<DuxReiNummariae revision="1">
	<wages>
		<wage id="1" major="2000" minor="0" period="Monthly" name="Burger King" currency="PLN" nextOccurOn="2019-05-01" accountId="1020"/>
		<wage id="2" major="5" minor="1500" period="Hourly" name="McDonald's" currency="USD" nextOccurOn="2019-05-02" accountId="1020"/>
		<wage id="3" major="25" minor="4500" period="Hourly" name="RadioShack" currency="USD" nextOccurOn="2019-05-03" accountId="1020"/>
	</wages>
	<bills>
		<bill id="1" major="15" minor="5500" period="Quarterly" name="Club Dues" currency="PLN" nextOccurOn="2019-05-04" accountId="1020"/>
		<bill id="2" major="29" minor="9500" period="Daily" name="Parking" currency="PLN" nextOccurOn="2019-05-05" accountId="1020"/>
		<bill id="3" major="2125" minor="1200" period="Monthly" name="Rent" currency="USD" nextOccurOn="2019-05-06" accountId="1020"/>
	</bills>
	<debts>
		<debt id="1" totalMajor="12000" totalMinor="7500" period="Monthly" name="Mastercard Credit Card" currency="PLN" minimumMajor="15" minimumMinor="9000" interest="40.15" nextOccurOn="2019-05-07" accountId="1020"/>
		<debt id="2" totalMajor="120000" totalMinor="5500" period="Monthly" name="Mortgage" currency="PLN" minimumMajor="1000" minimumMinor="0" interest="3.4" nextOccurOn="2019-05-08" accountId="1020"/>
		<debt id="3" totalMajor="30000" totalMinor="9500" period="Monthly" name="Visa Credit Card" currency="USD" minimumMajor="30" minimumMinor="1500" interest="34.15" nextOccurOn="2019-05-09" accountId="1020"/>
	</debts>
	<goals>
		<goal id="1" major="25" minor="9500" period="Weekly" name="Computer" currency="PLN" finalMajor="2500" finalMinor="9500" nextOccurOn="2019-05-10" accountId="1020"/>
		<goal id="2" major="1" minor="500" period="Daily" name="New Bike" currency="USD" finalMajor="1000" finalMinor="500" nextOccurOn="2019-05-11" accountId="1020"/>
		<goal id="3" major="231" minor="1500" period="Monthly" name="Vacation" currency="PLN" finalMajor="2310" finalMinor="1500" nextOccurOn="2019-05-12" accountId="1020"/>
	</goals>
	<nontracks>
		<nontrack id="1" major="20" minor="9500" period="Daily" name="Mine" currency="PLN" nextOccurOn="2019-05-13" accountId="1020"/>
		<nontrack id="2" major="20" minor="9500" period="Daily" name="Wife's" currency="PLN" nextOccurOn="2019-05-13" accountId="1020"/>
	</nontracks>
	<accounts>
		<account id="1000" name="Monies" type="Asset" major="0" minor="0" currency="PLN" closed="false"/>
		<account id="1010" name="Cash" type="Asset" major="1234" minor="5600" currency="PLN" closed="false" parentId="1000"/>
		<account id="1020" name="Chequeing" type="Asset" major="789" minor="1000" currency="USD" closed="true" parentId="1000"/>
		<account id="2010" name="Opening Balances" type="Capital" major="0" minor="0" currency="EUR" closed="false"/>
		<account id="3010" name="Job" type="Revenue" major="1234" minor="5600" currency="PLN" closed="false"/>
		<account id="4010" name="Visa Card" type="Liability" major="2000" minor="6300" currency="PLN" closed="true"/>
	</accounts>
	<ledgers openingAccountId="2010">
		<ledger id="1000"/>
		<ledger id="1010">
			<transaction id="1" date="2018-06-11" accountId="3010" entry="Cr" major="1234" minor="5600" currency="PLN" status="Reconciled"/>
			<transaction id="2" date="2018-07-11" accountId="3010" entry="Cr" major="1234" minor="5600" currency="PLN" status="Reconciled">Pay cheque 11 VII 2018</transaction>
			<transaction id="3" date="2018-08-11" accountId="3010" entry="Cr" major="1234" minor="5600" currency="PLN" status="Reconciled">Pay cheque 11 VIII 2018</transaction>
		</ledger>
		<ledger id="1020"/>
		<ledger id="2010"/>
		<ledger id="3010">
			<transaction id="1" date="2018-06-11" accountId="1010" entry="Dr" major="1234" minor="5600" currency="PLN" status="Reconciled"/>
			<transaction id="2" date="2018-07-11" accountId="1010" entry="Dr" major="1234" minor="5600" currency="PLN" status="Reconciled">Pay cheque 11 VII 2018</transaction>
			<transaction id="3" date="2018-08-11" accountId="1010" entry="Dr" major="1234" minor="5600" currency="PLN" status="Reconciled">Pay cheque 11 VIII 2018</transaction>
		</ledger>
		<ledger id="4010"/>
	</ledgers>
	<banks>
		<bank name="Community 1st Credit Union" closed="false">
			<account id="1010" type="Savings"/>
		</bank>
		<bank name="Home Federal" closed="true">
			<account id="1020" type="Chequeing"/>
			<account id="4010" type="Credit Card"/>
		</bank>
		<bank name="Millennium" closed="false"/>
	</banks>
</DuxReiNummariae>)~"};
	return budgetContents;
}

const char* drn::file_storage::tests::validEmptyContents()
{
	constexpr auto budgetContents{R"~(<?xml version="1.0" encoding="UTF-8"?>
<DuxReiNummariae revision="1">
	<wages/>
	<bills/>
	<debts/>
	<goals/>
	<nontracks/>
	<accounts/>
	<ledgers/>
	<banks/>
</DuxReiNummariae>)~"};
	return budgetContents;
}

const char* drn::file_storage::tests::validOpeningAccountNoTransactionsContents()
{
	constexpr auto budgetContents{R"~(<?xml version="1.0" encoding="UTF-8"?>
<DuxReiNummariae revision="1">
	<wages/>
	<bills/>
	<debts/>
	<goals/>
	<nontracks/>
	<accounts>
		<account id="1010" name="Cash" type="Asset" major="0" minor="0" currency="USD" closed="false"/>
	</accounts>
	<ledgers>
		<ledger id="1010"/>
	</ledgers>
	<banks/>
</DuxReiNummariae>)~"};
	return budgetContents;
}

// N.B. This is expected to be in step with validContents.
const Budget& drn::file_storage::tests::validBudget()
{
	static const Budget b{
		WageMap{
			{
				{
					BudgetSource{"McDonald's"},
					Wage{
						BudgetSource{"McDonald's"},
						Money{5, 1500u, Iso4217Codes::USD},
						EventFrequency::Hourly,
						{2019, 5, 2}
					}
				},
				{
					BudgetSource{"RadioShack"},
					Wage{
						BudgetSource{"RadioShack"},
						Money{25, 4500u, Iso4217Codes::USD},
						EventFrequency::Hourly,
						{2019, 5, 3}
					}
				},
				{
					BudgetSource{"Burger King"},
					Wage{
						BudgetSource{"Burger King"},
						Money{2000, 0u, Iso4217Codes::PLN},
						EventFrequency::Monthly,
						{2019, 5, 1}
					}
				}
			}
		},
		BillMap{
			{
				{
					BudgetSource{"Club Dues"},
					Bill{
						BudgetSource{"Club Dues"},
						Money{15, 5500u, Iso4217Codes::PLN},
						EventFrequency::Quarterly,
						{2019, 5, 4}
					}
				},
				{
					BudgetSource{"Rent"},
					Bill{
						BudgetSource{"Rent"},
						Money{2125, 1200u, Iso4217Codes::USD},
						EventFrequency::Monthly,
						{2019, 5, 6}
					}
				},
				{
					BudgetSource{"Parking"},
					Bill{
						BudgetSource{"Parking"},
						Money{29, 9500u, Iso4217Codes::PLN},
						EventFrequency::Daily,
						{2019, 5, 5}
					}
				}
			}
		},
		DebtMap{
			{
				{
					BudgetSource{"Mortgage"},
					Debt{
						BudgetSource{"Mortgage"},
						Money{1000, 0u, Iso4217Codes::PLN},
						EventFrequency::Monthly,
						{2019, 5, 8},
						Money{120000, 5500u, Iso4217Codes::PLN},
						Percentage{3.4}
					}
				},
				{
					BudgetSource{"Visa Credit Card"},
					Debt{
						BudgetSource{"Visa Credit Card"},
						Money{30, 1500u, Iso4217Codes::USD},
						EventFrequency::Monthly,
						{2019, 5, 9},
						Money{30000, 9500u, Iso4217Codes::USD},
						Percentage{34.15}
					}
				},
				{
					BudgetSource{"Mastercard Credit Card"},
					Debt{
						BudgetSource{"Mastercard Credit Card"},
						Money{15, 9000u, Iso4217Codes::PLN},
						EventFrequency::Monthly,
						{2019, 5, 7},
						Money{12000, 7500u, Iso4217Codes::PLN},
						Percentage{40.15}
					}
				}
			}
		},
		GoalMap{
			{
				{
					BudgetSource{"Computer"},
					Goal{
						BudgetSource{"Computer"},
						Money{25, 9500u, Iso4217Codes::PLN},
						EventFrequency::Weekly,
						{2019, 5, 10},
						Money{2500, 9500u, Iso4217Codes::PLN}
					}
				},
				{
					BudgetSource{"Vacation"},
					Goal{
						BudgetSource{"Vacation"},
						Money{231, 1500u, Iso4217Codes::PLN},
						EventFrequency::Monthly,
						{2019, 5, 12},
						Money{2310, 1500u, Iso4217Codes::PLN}
					}
				},
				{
					BudgetSource{"New Bike"},
					Goal{
						BudgetSource{"New Bike"},
						Money{1, 500u, Iso4217Codes::USD},
						EventFrequency::Daily,
						{2019, 5, 11},
						Money{1000, 500u, Iso4217Codes::USD}
					}
				}
			}
		},
		{
			{
				{
					BudgetSource{"Mine"},
					Nontrack{
						BudgetSource{"Mine"},
						Money{20, 9500u, Iso4217Codes::PLN},
						EventFrequency::Daily,
						{2019, 5, 13}
					}
				},
				{
					BudgetSource{"Wife's"},
					Nontrack{
						BudgetSource{"Wife's"},
						Money{20, 9500u, Iso4217Codes::PLN},
						EventFrequency::Daily,
						{2019, 5, 13}
					}
				}
			}
		}
	};
	return b;
}

// N.B. This is expected to be in step with validContents.
const GeneralLedger& drn::file_storage::tests::validGeneralLedger()
{
	static const AccountNumber moniesNumber{1000u};
	static const AccountCode monies{moniesNumber, "Monies"};
	static const AccountCode cash{AccountNumber{1010u}, "Cash", moniesNumber};
	static const AccountCode chequeing{AccountNumber{1020u}, "Chequeing", moniesNumber};
	static const AccountCode openingBalances{AccountNumber{2010u}, "Opening Balances"};
	static const AccountCode job{AccountNumber{3010u}, "Job"};
	static const AccountCode visa{AccountNumber{4010u}, "Visa Card"};
	static const GeneralLedger gl{
		{
			{
				monies,
				LedgerAccount{
					Account{
						AccountTypes::Asset,
						monies,
						Money{0, 0u, Iso4217Codes::PLN}
					},
					map<TransactionNumber, Transaction>{}
				}
			},
			{
				cash,
				LedgerAccount{
					Account{
						AccountTypes::Asset,
						cash,
						Money{1234, 5600u, Iso4217Codes::PLN}
					},
					map<TransactionNumber, Transaction>{
						{
							TransactionNumber{1u},
							Transaction{
								QDate{2018, 6, 11},
								cash, // debit
								job, // credit
								Money{1234, 5600, Iso4217Codes::PLN},
								{},
								TransactionNumber{1u},
								TransactionStatuses::Reconciled
							}
						},
						{
							TransactionNumber{2u},
							Transaction{
								QDate{2018, 7, 11},
								cash, // debit
								job, // credit
								Money{1234, 5600, Iso4217Codes::PLN},
								QStringLiteral("Pay cheque 11 VII 2018"),
								TransactionNumber{2u},
								TransactionStatuses::Reconciled
							}
						},
						{
							TransactionNumber{3u},
							Transaction{
								QDate{2018, 8, 11},
								cash, // debit
								job, // credit
								Money{1234, 5600, Iso4217Codes::PLN},
								QStringLiteral("Pay cheque 11 VIII 2018"),
								TransactionNumber{3u},
								TransactionStatuses::Reconciled
							}
						}
					}
				}
			},
			{
				chequeing,
				LedgerAccount{
					Account{
						AccountTypes::Asset,
						chequeing,
						Money{789, 1000u, Iso4217Codes::USD},
						true
					},
					map<TransactionNumber, Transaction>{}
				}
			},
			{
				job,
				LedgerAccount{
					Account{
						AccountTypes::Revenue,
						job,
						Money{1234, 5600u, Iso4217Codes::PLN}
					},
					map<TransactionNumber, Transaction>{
						{
							TransactionNumber{1u},
							Transaction{
								QDate{2018, 6, 11},
								cash, // debit
								job, // credit
								Money{1234, 5600, Iso4217Codes::PLN},
								{},
								TransactionNumber{1u},
								TransactionStatuses::Reconciled
							}
						},
						{
							TransactionNumber{2u},
							Transaction{
								QDate{2018, 7, 11},
								cash, // debit
								job, // credit
								Money{1234, 5600, Iso4217Codes::PLN},
								QStringLiteral("Pay cheque 11 VII 2018"),
								TransactionNumber{2u},
								TransactionStatuses::Reconciled
							}
						},
						{
							TransactionNumber{3u},
							Transaction{
								QDate{2018, 8, 11},
								cash, // debit
								job, // credit
								Money{1234, 5600, Iso4217Codes::PLN},
								QStringLiteral("Pay cheque 11 VIII 2018"),
								TransactionNumber{3u},
								TransactionStatuses::Reconciled
							}
						}
					}
				}
			},
			{
				visa,
				LedgerAccount{
					Account{
						AccountTypes::Liability,
						visa,
						Money{2000, 6300u, Iso4217Codes::PLN},
						true
					},
					map<TransactionNumber, Transaction>{}
				}
			},
			{
				openingBalances,
				{
					{
						AccountTypes::Capital,
						openingBalances,
						{0, 0u, Iso4217Codes::EUR}
					},
					{}
				}
			}
		},
		openingBalances
	};
	return gl;
}

const Budget& drn::file_storage::tests::validBudgetOpeningAccountNoTransactions()
{
	static const Budget b{};
	return b;
}

const GeneralLedger&
		drn::file_storage::tests::validGeneralLedgerOpeningAccountNoTransactions()
{
	static const AccountCode cash{AccountNumber{1010u}, "Cash"};
	static const GeneralLedger gl{
		{
			{
				cash,
				LedgerAccount{
					Account{
						AccountTypes::Asset,
						cash,
						Money{0, 0u, Iso4217Codes::USD}
					},
					{}
				}
			}
		},
		{}
	};
	return gl;
}

// N.B. This is expected to be in step with validContents.
const BankMap& drn::file_storage::tests::validBanks()
{
	static const BankName homeFederalName{"Home Federal"};
	static const BankName c1stName{"Community 1st Credit Union"};
	static const BankName millenniumName{"Millennium"};
	static const BankMap b{
		{
			{
				homeFederalName,
				Bank{
					homeFederalName,
					{AccountNumber{1020u}, AccountNumber{4010u}},
					true
				}
			},
			{c1stName, Bank{c1stName, {AccountNumber{1010u}}}},
			{millenniumName, Bank{millenniumName}}
		}
	};
	return b;
}

// N.B. This is expected to be in step with validContents.
const map<
	BankName,
	map<AccountNumber, SupportedAccountTypes>
>& drn::file_storage::tests::validSupportedAccountTypes()
{
	static const map<BankName, map<AccountNumber, SupportedAccountTypes>> sat{
		{
			{
				BankName{"Home Federal"},
				{
					{
						{AccountNumber{1020u}, SupportedAccountTypes::Chequeing},
						{AccountNumber{4010u}, SupportedAccountTypes::CreditCard}
					}
				}
			},
			{
				BankName{"Community 1st Credit Union"},
				{
					{
						{AccountNumber{1010u}, SupportedAccountTypes::Savings}
					}
				}
			}
		}
	};
	return sat;
}

// N.B. This is expected to be in step with validContents.
TypeIndexMap<BudgetSource, AccountCode> drn::file_storage::tests::validBudgetCodes()
{
	TypeIndexMap<BudgetSource, AccountCode> bc{};

	//{ Add the Wage Items

	bc.add<Wage>(BudgetSource{"Burger King"}, AccountCode{AccountNumber{1020u}});
	bc.add<Wage>(BudgetSource{"McDonald's"}, AccountCode{AccountNumber{1020u}});
	bc.add<Wage>(BudgetSource{"RadioShack"}, AccountCode{AccountNumber{1020u}});

	//}

	//{ Add the Bill Items

	bc.add<Bill>(BudgetSource{"Club Dues"}, AccountCode{AccountNumber{1020u}});
	bc.add<Bill>(BudgetSource{"Parking"}, AccountCode{AccountNumber{1020u}});
	bc.add<Bill>(BudgetSource{"Rent"}, AccountCode{AccountNumber{1020u}});

	//}

	//{ Add the Debt Items

	bc.add<Debt>(BudgetSource{"Mastercard Credit Card"}, AccountCode{AccountNumber{1020u}});
	bc.add<Debt>(BudgetSource{"Mortgage"}, AccountCode{AccountNumber{1020u}});
	bc.add<Debt>(BudgetSource{"Visa Credit Card"}, AccountCode{AccountNumber{1020u}});

	//}

	//{ Add the Goal Items

	bc.add<Goal>(BudgetSource{"Computer"}, AccountCode{AccountNumber{1020u}});
	bc.add<Goal>(BudgetSource{"New Bike"}, AccountCode{AccountNumber{1020u}});
	bc.add<Goal>(BudgetSource{"Vacation"}, AccountCode{AccountNumber{1020u}});

	//}

	//{ Add the Nontrack Items

	bc.add<Nontrack>(BudgetSource{"Mine"}, AccountCode{AccountNumber{1020u}});
	bc.add<Nontrack>(BudgetSource{"Wife's"}, AccountCode{AccountNumber{1020u}});

	//}

	return bc;
}
