const enum EActionPosition{
	ACTIONBAR = -1,
	BOTH = 0,
	PASSAGE = 1
}

var actAdd = function(macroContext:TwineSugarCube.MacroContext,labelRaw:string,contents:string,position?:EActionPosition,flags?:ActFlags){

	const pc = State.variables.pc;

	let label = flags.label ?? labelRaw;
	let _styleClass = 'action';
	let _tooltip = '';

	let _act_contents = flags.contents ?? contents;
	let _capture_vars = flags.capture ?? [];

	_capture_vars.push('_autoCapture')//<!-- The vars that always get captured by actions -->

	if(flags.template){
		if(Array.isArray(flags.template)){
			for(const templateId of flags.template)
				flags = setup.getActionTemplate(templateId)(flags);
		}
		else
			flags = setup.getActionTemplate(flags.template)(flags);
	}

	/*
		Deprecated. Use templates instead.
	*/
	if('action' in flags){
		flags = Object.assign({},flags,setup.getGenericActionApplied(flags.action))
		_act_contents += `<<actionApply '${flags.action}'>>`;
	}

	if(flags.disabled){
		_tooltip = flags.disabled ?? '';
		_styleClass += ' disabled';
		_act_contents = ''
	}

	if(flags.hidden){
		return;
	}

	if('time' in flags){
		if(flags.time > 0)
			_act_contents = `<<addtime ${flags.time}>>${_act_contents}`;
		label += ` (${setup.durationToString(Math.abs(flags.time))})`;
	}

	if('moodlet' in flags){
		let _moodletData = Moodlet.get(flags.moodlet);
		_tooltip += 'This would likely lead to you getting the effect '+_moodletData.title+'.';
	}

	if('mood' in flags){
		if(pc.mood < flags.mood){
			_tooltip += 'Your mood is too low to do this.'
			_styleClass += ' mood disabled'
			_act_contents = ''
		}else{
			_tooltip += 'Your mood is high enough (>='+flags.mood+') to do this.'
			_styleClass += ' mood'
		}
	}

	if('arousal' in flags){
		if(pc.horny < flags.arousal){
			_tooltip += 'Your arousal is too low ('+pc.horny+'/'+flags.arousal+') to do this.'
			_styleClass += ' arousal disabled'
			_act_contents = ''
		}else{
			_tooltip += 'Your arousal is high enough (>='+flags.arousal+') to do this.'
			_styleClass += ' arousal'
		}
	}

	/*if('fetish' in flags){
		let _actFetishes = flags.fetish
		<<for _actFetish range _actFetishes>>
			if(pc.fetish(_actFetish) < 0){
				let _tooltip += _actFetish+ ': You can\'t do this because of your fetish-settings (you can change them in the character-menu).'
				let _styleClass += ' fetish disabled'
				let _act_contents = ''
			}
		<</for>>
	}*/

	//<!-- Skills -->
	if('skillRequirment' in flags){
		let _skillsMessage = ''
		let _skillsEnable = true
		for(const[_skillId, _skillMin] of Object.entries(flags.skillRequirment)){
			if(pc.skillLevel(_skillId) >= _skillMin){
				_skillsMessage += 'Your skill '+_skillId+' of '+_skillMin+'+ enables you to do this.'
			}else{
				_skillsMessage += 'Your skill '+_skillId+' needs to be '+_skillMin+'+ to do this.'
				_skillsEnable = false
			}
		}
		_tooltip += _skillsMessage
		if(_skillsEnable){
			_styleClass += ' skill'
		}else{
			_styleClass += ' skill disabled'
			_act_contents = ''
		}
	}

	let willpowerCost = 0;

	//#region Personality
		if(flags.personality){

			if(flags.willpower){
				console.error('personality and willpower must not be declare at the same time in actAdd: (label, flags)',label,flags);
			}

			let personality_willpower = 0;
			let personality_action = '';

			for(const [personalityId, personalityRequirementOrAction] of Object.entries(flags.personality)){
				let personalityRequirement:PersonalityRequirement;
				if(typeof personalityRequirementOrAction == "string")
					personalityRequirement = pc.personalityScale(personalityId).actions[personalityRequirementOrAction];
				else
					personalityRequirement = personalityRequirementOrAction;

				const expectedPersonalityEffect = pc.personalityScale(personalityId).effectOfAction(personalityRequirement);
				if(expectedPersonalityEffect.willpower > 0)
					personality_willpower += expectedPersonalityEffect.willpower;
				if(expectedPersonalityEffect.shift != 0)
					personality_action += `<<run $pc.personalityScale('${personalityId}').current += ${expectedPersonalityEffect.shift}>>`;
			}

			if(personality_willpower){
				_styleClass += ""
				//_act_contents = ` <<run $pc.willpower -= ${personality_willpower}>>${personality_action}${_act_contents}`;
				//label = `${label} (${Math.ceil(personality_willpower)} willpower)`;
				_act_contents = personality_action+_act_contents;
				willpowerCost = personality_willpower;
			}
		}
	//#endregion

	//#region Willpower
		if(flags.willpower){
			//let _willpower_cost = 0;
			if(typeof flags.willpower == "number"){
				willpowerCost = flags.willpower
			}else{
				willpowerCost = setup.func('willpower','cost',flags.willpower)
			}
		}

		if(willpowerCost > 0){

			label += " ("+willpowerCost+")"
			_styleClass += ' willpower'
			_act_contents = ` <<run $pc.willpower -= ${willpowerCost}>>${_act_contents}`;
			if(willpowerCost > pc.willpower){
				_styleClass += ' willpower_danger'
				_tooltip = "This will negatively affect your mental health."
			}

		}

		
	//#endregion

	//<!-- Money Cost -->
	if('cost' in flags){
		if(flags.cost.cash){
			let _cashCost = flags.cost.cash;
			label += " (<b>"+Math.abs(_cashCost).toLocaleString()+" ₽</b> Cash)"
			if(Math.abs(_cashCost) > State.variables.finances.cash){
				_styleClass += ' cost cost_disabled disabled'
				_act_contents = ''
				_tooltip = "You don\'t have enough cash to perform this action."
			}else{
				_styleClass += ' cost'
				if(_cashCost > 0){
					_act_contents = "<<set $finances.cash -= "+_cashCost+">>" + _act_contents;
				}
			}
		}else if(flags.cost.bank){
			let _bankCost = flags.cost.bank;
			label += " (<b>"+Math.abs(_bankCost).toLocaleString()+" ₽</b> from Bank Account)"
			if(!State.variables.finances.hasBankAccount){
				_styleClass += ' cost cost_disabled disabled';
				_act_contents = '';
				_tooltip = "You don't have a bank account.";
			}else if(Math.abs(_bankCost) > State.variables.finances.bankAvailable){
				_styleClass += ' cost cost_disabled disabled'
				_act_contents = ''
				_tooltip = "You don\'t have enough money on your bank account to perform this action."
			}else{
				_styleClass += ' cost'
				if(_bankCost > 0){
					_act_contents = "<<set $finances.bank -= "+_bankCost+">>" + _act_contents;
				}
			}
		}else if(flags.cost.both){
			let flagsOfCashButton = clone(flags);
			flagsOfCashButton.cost = {cash: flags.cost.both};
			let _contentsOfCashButton  = clone(contents)
			let flagsOfBankButton = clone(flags)
			flagsOfBankButton.cost = {bank: flags.cost.both}
			let _contentsOfBankButton  = clone(contents)

			actAdd(macroContext,label,_contentsOfCashButton,position,flagsOfCashButton);
			actAdd(macroContext,label,_contentsOfBankButton,position,flagsOfBankButton);
			return;
		}
	}

	//<!-- Do Once Every n time-units -->
	if('repeatReset' in flags){
		let _uniqueActionId = flags.repeatReset.id ?? (State.temporary.thisMainPassage + '~' + labelRaw)//<!-- Use the raw label so it doesn't get fucked up by willlpower calculations -->
		let _repeatResetCooldownEnd = State.variables.actions[_uniqueActionId]?.cooldownEnd ?? 0
		if(_repeatResetCooldownEnd < State.variables.time.now.getTime()){
			if(flags.repeatReset.days){
				_act_contents = "<<set $actions['"+_uniqueActionId+"'] = {cooldownEnd:$time.dayWithOffsetS("+flags.repeatReset.days+")}>>" + _act_contents;
			}
		}else{
			return;
		}
	}

	//<!-- items -->
	if('items' in flags){
		let _missingItems = ''
		for(const[_itemKey, _itemAmount] of Object.entries(flags.items)){
			if(_itemAmount > State.variables.inventory.get(_itemKey))
				_missingItems += '<br/>'+State.variables.inventory.metadata(_itemKey).label+': '+_itemAmount
			else if(_itemAmount > 0)
				_act_contents = "<<run $inventory.dec('"+_itemKey+"',"+_itemAmount+")>>" + _act_contents
			
		}
		if(_missingItems){
			_styleClass += ' disabled'
			_act_contents = ''
			_tooltip = 'You are missing the following:'+_missingItems+"x"
		}
	}


	if(_act_contents){
		_act_contents = (flags.contents_header ?? '') + _act_contents + (flags.contents_footer ?? '');
	}

	if(position == EActionPosition.BOTH || position === EActionPosition.ACTIONBAR){

		let _ab_label = flags.ab_label ?? label;
		let _priority = flags.priority ?? 0;

		let _capture_vars_actionBar = {};
		for(const _capture_var of _capture_vars)
			_capture_vars_actionBar[_capture_var] = clone(State.getVar(_capture_var))
		

		State.temporary.actions ??= [];
		State.temporary.actions.push( new setup.Action(
			{
				passage: passage(),
				label: _ab_label,
				contents: _act_contents,
				priority: _priority,
				captured: _capture_vars_actionBar,
				styleClass: _styleClass,
				tooltip: _tooltip,
				image: flags.image
			})
		);
	}
	if(position == EActionPosition.BOTH || position === EActionPosition.PASSAGE){

		let _linkMarkup = `<<link '${label}'>>${_act_contents}<</link>>`;
			
		if(_capture_vars.length > 0){
			_linkMarkup = '<<capture '+_capture_vars.join(', ')+'>>'+_linkMarkup+'<</capture>>';
		}

		const output = `<<tooltip 'span' '${_styleClass}' '${_tooltip.replace("'",'&#39;')}'>>${_linkMarkup}<</tooltip>>`

		jQuery(macroContext.output).wiki(output);
		
	}

}



Macro.add('act', {
	skipArgs : false,
	tags:[],
	handler  : function () {
		try {
	
			let label:string = this.args[0];
			const position:EActionPosition = this.args[1] ?? State.temporary.actionBarOverride ?? EActionPosition.ACTIONBAR;
			let flags:ActFlags = this.args[2] ?? {};

			actAdd(this,label,this.payload[0].contents,position,flags);
		}
		catch (ex) {
			return this.error('ERROR in act-widget: ' + ex.message);
		}
	}
});


Macro.add('actCLA', {
	skipArgs : false,
	tags:[],
	handler  : function () {
		try {
	
			let label:string = this.args[0];
			const position:EActionPosition = this.args[1] ?? State.temporary.actionBarOverride ?? EActionPosition.ACTIONBAR;
			let flags:ActFlags = this.args[2] ?? {};

			flags.contents_header = '<<set _actions = []>><<replace ".passage">>';
			flags.contents_footer = '<</replace>><<actionsRefresh>><<sidebarUpdate>>';

			actAdd(this,label,this.payload[0].contents,position,flags);
		}
		catch (ex) {
			return this.error('ERROR in actCLA-widget: ' + ex.message);
		}
	}
});