setup.financesBankTransactionLength = 50;

class Finances{
	_cash = 0;

	get available(){
		return Math.max(this.cash, this.bankAvailable);
	}

	get cash(){return this._cash;}
	set cash(v){
		if(typeof v === 'string')
			v = parseInt(v);
		if((typeof v !== "number") || Number.isNaN(v)){
			console.error('Tried to set cash to non-number',v);
			return;
		}
		console.log("Cash set to",v);
		this._cash = parseInt(v);
	}

	_bank = 0;
	get bank(){return this._bank;}
	set bank(v){
		if(typeof v === 'string')
			v = parseInt(v);
		if((typeof v !== "number") || Number.isNaN(v)){
			console.error('Tried to set bank to non-number',v);
			return;
		}
		console.log("Bank set to",v);
		this._bank = parseInt(v);
	}

	hasBankAccount = 0;
	bankOverdraftMax = 0;

	_bankTransactions = [];
	bankTransactionRegister(day,balance,desc){
		this._bankTransactions.push({day:day,balance:balance,desc:desc});
		this._bankTransactions.keepSize(setup.financesBankTransactionLength);
		this._bank += balance;
	}

	get bankAvailable(){
		if(!this.hasBankAccount)
			return 0;
		return this.bank + this.bankOverdraftMax;
	}

	
	/**
	 * Called by $time
	 * @date 9/9/2023 - 3:15:56 PM
	 */
	execute_every_1_day(){
		this.bankScheduledTransactionsExecute();
	}
	
	/**
	 * Transactions which should be executed on a regular basis, such as rent or income.
	 * @date 9/9/2023 - 10:18:21 AM
	 *
	 * @type {{}}
	 * @example
	 * 	{
	 * 		rent_city_residential:{
	 * 			balance: -3000, //Negative numbers are taken from the account
	 * 			mode: 'nth of month', //Once a month at day n
	 * 			modeParameter:{
	 * 				day: 1 //day n is 1
	 * 			},
	 * 			nextExecution: 34, //the next execution is scheduled for day 34
	 * 			desc: 'Rent payment' //What should be displayed to the user
	 * 		}
	 * 	}
	 */
	_bankScheduledTransactions = {}

	bankScheduledTransactionsExecute(today = undefined){
		const time = State.variables.time;
		today ??= time.daystart;

		for (const [transactionKey, transactionData] of Object.entries(this._bankScheduledTransactions)) {
			let executionDay = transactionData.nextExecution;
			if(executionDay <= today){
				this.bankTransactionRegister(today,transactionData.balance,transactionData.desc);
				this._bankScheduledTransactions[transactionKey].nextExecution = this.bankScheduledTransactionsNextExecution(transactionData.mode,transactionData.modeParameter);
			}
		}
	}

	
	/**
	 * Returns the daystart of the next execution
	 * @date 9/10/2023 - 1:18:01 PM
	 *
	 * @param {string} mode
	 * @param {*} modeParameter
	 * @returns {number}
	 */
	bankScheduledTransactionsNextExecution(mode,modeParameter){
		const time = State.variables.time;
		switch(mode){
			case 'nth of month':
				let dayN = modeParameter?.day ?? 1;
				return time.daystartNextAtNthOfMonth(dayN);
			case 'once':
				return -1;
			default:
				console.error('Mode not reckognized in $finances.bankScheduledTransactionsNextExecution()',mode);
				return 0;
		}
	}

	bankScheduledTransactionsRegister(id,balance,mode,modeParameter,nextExecution,desc){
		this._bankScheduledTransactions[id] = {
			balance: balance,
			mode: mode,
			modeParameter:modeParameter,
			nextExecution: (nextExecution >= 0 ? nextExecution : this.bankScheduledTransactionsNextExecution(mode,modeParameter)),
			desc: desc
		}
	}

	bankScheduledTransactionsUnregister(id){
		delete this._bankScheduledTransactions[id];
	}



	constructor(){}

	_init(finances){
		Object.keys(finances).forEach(function (pn) {
			this[pn] = clone(finances[pn]);
		}, this);

		return this;
	}

	clone = function () {
		return (new Finances())._init(this);
	};

	toJSON = function () {
		var ownData = {};
		Object.keys(this).forEach(function (pn) {
			if(typeof this[pn] !== "function")
				ownData[pn] = clone(this[pn]);
		}, this);
		return JSON.reviveWrapper('(new Finances())._init($ReviveData$)', ownData);
	};
}

window.Finances = Finances;
