#pragma once

#include "Attacker.h"
#include "Weapons/BaseWeapon.h"

namespace mechanics {
	class Attackable {
	public:
		//base health
		Attackable() : mHP(0) {
		}

		virtual bool canBeDestroyed() {
			return true;
		}

		virtual bool isAlive() const {
			return (mHP > 0);
		}

		virtual float maximumHP() const = 0;

		virtual float HP() const {
			return mHP;
		}

		virtual void HP(float value) {
			value=gge::utils::Limit(value, 0.f, maximumHP());
			mHP = value;
		}

		virtual void IncHP(float amount) {
			mHP = gge::utils::Limit(mHP+amount, 0.f, maximumHP());
		}

		virtual bool Dodge(Attacker *attacker, BaseWeapon *weapon) {
			return false;
		}

		virtual bool Parry(Attacker *attacker, BaseWeapon *weapon) {
			return false;
		}

		virtual bool Block(Attacker *attacker, BaseWeapon *weapon, float damage) {
			return false;
		}

		//per damage
		virtual float XPReward() const = 0;

		virtual float Damage(Attacker *attacker, BaseWeapon *weapon, float damage) {
			if(Dodge(attacker, weapon) || Parry(attacker, weapon) || Block(attacker, weapon, damage)) {
				return 0.0f;
			}

			float calculatedDamage = CalculateDamageReduction(attacker, weapon, damage);

			if(calculatedDamage > 0) {
				IncHP(-calculatedDamage);

				if(!isAlive()) {
					Killed(attacker, weapon);
					return calculatedDamage;
				}
			}

			CalculateStagger(attacker, weapon, damage, calculatedDamage);

			return std::max(0.f,calculatedDamage);
		}

		virtual float CalculateDamageReduction(Attacker *attacker, BaseWeapon *weapon, float damage) {
			return damage;
		}

		virtual float CalculateStagger(Attacker *attacker, BaseWeapon *weapon, float damage, float reducedDamage) {
			float staggerPoint = damage - reducedDamage;

			staggerPoint += attacker->staggerBonus(damage, staggerPoint);

			if(staggerPoint <= 0) {
				return 0.0f;
			}

			return staggerPoint;
		}

		virtual void Killed(Attacker *attacker, BaseWeapon *weapon) {
			if(attacker == NULL) {
				return;
			}

			attacker->increaseKillcount();
		}

	protected:
		float mHP;
	};
}