'use strict';
const util = require('util');

/**
 * Reusable helper functions and defaults for effects.
 * Pass in the attribute/whatever else changes, along with the config.
 */

const defaultDuration = 10 * 1000;

const getTargetName = config => config.player ?
	config.player.getName() : config.target.getShortDesc('en');

const debuff = (attribute, config) => {
	config.magnitude = -config.magnitude;
	return buff(attribute, config);
};

const buff = (attribute, config) => {
	util.log('Buffing ' + attribute + ': ', getTargetName(config));
	util.log(config.magnitude);

	const original = config.target.getAttribute(attribute);
	return {
		duration: config.duration,
		activate: () => {
			config.target.setAttribute(attribute, original + config.magnitude);
			if (config.activate) { config.activate(); }
		},
		deactivate: () => {
			if (config.target) {
				config.target.setAttribute(attribute, original);
				if (config.deactivate) { config.deactivate(); }
			}
		}
	};
};

const buffWithMax = (attribute, config) => {
	util.log('Buffing ' + attribute + ': ', getTargetName(config));
	util.log(config.magnitude);

	const max = 'max_' + attribute;
	const original = config.player.getAttribute(attribute);
	const originalMax = config.player.getAttribute(max);

	return {
		activate: () => {
			config.player.setAttribute(max, originalMax + config.magnitude);
			config.player.setAttribute(attribute, original + config.magnitude);
		},
		deactivate: () => {
			config.player.setAttribute(max, originalMax);
			config.player.setAttribute(attribute, Math.min(originalMax, config.player.getAttribute(attribute)));
			if (config.deactivate) { config.deactivate(); }
		},
		duration: config.duration,
		event: config.event

	};
};

const multiply = (attribute, config) => {
	util.log('Multiplying ' + attribute + ': ', getTargetName(config));
	util.log(config.magnitude);

	const original = config.target.getAttribute(attribute);
	return {
		duration: config.duration || defaultDuration,
		activate: () => {
			config.target.setAttribute(attribute, original * config.magnitude);
			if (config.activate) { config.activate(); }
		},
		deactivate: () => {
			if (config.target) {
				config.target.setAttribute(attribute, original);
				if (config.deactivate) { config.deactivate(); }
			}
		}
	};
};

const Effects = {
  /**
   * Slow
	 * config.target: NPC to slow
	 * config.magnitude: amount to slow by (.5 would be half)
	 * [config.duration]: time in ms to slow for
	 * [config.deactivate]: function to execute after duration is over
   */
  slow: config => multiply('speed', config),

	/**
	 * Haste
	 * config.player: Player doing the targeting (or hasting themselves)
	 * config.targer: Player targeted
	 * config.magnitude
	 * [config.duration]: time in ms to haste for
	 * [config.deactivate]: function to execute after haste
	 */
	haste: config => {
		if (!config.target) { config.target = config.player; }
		return multiply('quickness', config);
	},

  /**
   * Health boost
	 * config.player: player whose health is boosted
   * config.magnitude: amount to boost health by
   * [config.duration]: amount of time to boost health
   * [config.event]: event to trigger health boost
   */
  health_boost:  config => buffWithMax('health', config),

	fortify: config => {
		if (!config.target) { config.target = config.player; }
		return buff('stamina', config);
	},

	regen: config => {
		const stat = config.stat || 'health';
		const max = 'max_' + stat;
		const attr = stat === 'sanity' ? 'willpower' : 'stamina';
		const isFeat = config.isFeat;

		let regenHandle = null;

		return {
			activate: bonus => {
	      bonus = bonus || config.bonus || 1;
	      const self = config.player;
	      const regenInterval = config.interval || 2000;

				if (stat !== 'energy') {
					const energyConfig = {
						player: self,
					  interval: 1000,
						stat: 'energy'
					}
					self.addEffect('recuperating', Effects.regen(energyConfig));
				}

	      regenHandle = setInterval(() => {
	        const current = self.getAttribute(stat);

	        let regenerated = Math.floor(Math.random() * self.getAttribute(attr) + bonus);
	        regenerated = Math.min(self.getAttribute(max), current + regenerated);

	        util.log(self.getName() + ' has regenerated up to ' + regenerated + ' ' + stat + '.');
	        self.setAttribute(stat, regenerated);

	        if (regenerated === self.getAttribute(max)) {
						util.log(self.getName() + ' has reached ' + max);
	          clearInterval(regenHandle);
	        }
	      }, regenInterval);
    	},

			deactivate: () => {
				const isHealth = stat === 'health';
				const verb = getRegenVerb(isHealth, isFeat);
				clearInterval(regenHandle);
				if (stat === 'energy') { return; }
				self.say("<blue>You stop " + verb + '.</blue>');
				if (config.callback) { config.callback(); }
			},
		};
	},

};

function getRegenVerb(isHealth, isFeat) {
	if (isHealth && isFeat) { return 'regenerating'; }
	if (isHealth) { return 'resting'; }
	return 'meditating';
}

exports.Effects = Effects;

@@ -3546,16 +3546,48 @@
 .isFeat;
+%0A%09%09const player = config.player;
 %0A%0A%09%09let 
@@ -3689,43 +3689,8 @@
  1;%0A
-%09      const self = config.player;%0A
 %09   
@@ -3813,14 +3813,8 @@
 ayer
-: self
 ,%0A%09%09
@@ -3867,20 +3867,22 @@
 %09%7D%0A%09%09%09%09%09
-self
+player
 .addEffe
@@ -4003,20 +4003,22 @@
 rrent = 
-self
+player
 .getAttr
@@ -4085,20 +4085,22 @@
 dom() * 
-self
+player
 .getAttr
@@ -4153,20 +4153,22 @@
 ath.min(
-self
+player
 .getAttr
@@ -4214,36 +4214,38 @@
        util.log(
-self
+player
 .getName() + ' h
@@ -4311,20 +4311,22 @@
         
-self
+player
 .setAttr
@@ -4381,20 +4381,22 @@
 ted === 
-self
+player
 .getAttr
@@ -4424,20 +4424,22 @@
 til.log(
-self
+player
 .getName
@@ -4743,12 +4743,14 @@
 %09%09%09%09
-self
+player
 .say

Fix reference error by moving player var to outer scope.