#include "Item.h"
#include "Artisan.h"

namespace mechanics {
	Item::Item(assets::Item &provider, Animator &given_animator) : mProvider(provider), animator(given_animator), mLastUsedTime(0) {
	}

	assets::Item &Item::provider() const {
		return mProvider;
	}

	std::string Item::name() const {
		return mProvider.ID;
	}

	bool Item::isEquipable() {
		return true;
	}

	bool Item::isActive() const {
		return mIsActive;
	}

	float Item::lastUsedTime() const {
		return mLastUsedTime;
	}

	bool Item::canBeUsed() const {
		if(cooldown() > 0 && currentGameTime - mLastUsedTime <= cooldown()) { 
			return false;
		}

		if(!wielder())
			return false;

		if(wielder()->stamina()<mProvider.staminaCost) {
			return false;
		}

		return true;
	}

	void Item::use(float cooldownMod) {
		mLastUsedTime = currentGameTime-cooldown(); //cd is now 0
		mLastUsedTime += cooldownMod * cooldown(); 
		wielder()->addStamina(-mProvider.staminaCost);
	}

	void Item::wielder(Human *human) {
		mWielder = human;
	}

	Human *Item::wielder() const {
		return mWielder;
	}

	bool Item::canParry() const {
		return false;
	}

	bool Item::canBlock() const {
		return false;
	}

	float Item::attackDamage() const {
		float damage = provider().damage;

		if(wielder() != NULL) {
			damage += (wielder()->str() * provider().damageStrModifier) + (wielder()->dex() * provider().damageDexModifier) + (wielder()->level() * provider().damageLvlModifier);
		}

		return damage;
	}

	float Item::attackRange() const {
		float range = provider().range;

		if(wielder() != NULL) {
			range += (wielder()->str() * provider().rangeStrModifier);
		}

		return range;
	}

	float Item::cooldown() const {
		float cooldown = provider().CD;

		if(wielder() != NULL) {
			cooldown -= (wielder()->spe() * provider().CDSpeModifier) - (wielder()->level() * provider().CDLvlModifier);
		}

		return std::max(100.f,cooldown);
	}

	float Item::attackPrecision() const {
		float precision = provider().precision;

		if(wielder() != NULL) {
			precision += (wielder()->acc() * provider().precisionAccModifier) + (wielder()->level() * provider().precisionLvlModifier);
		}

		return precision;
	}

	float Item::parryPrecision() const {
		float parry = provider().parry;

		if(wielder() != NULL) {
			parry += (wielder()->acc() * provider().parryAccModifier) + (wielder()->intl() * provider().parryIntlModifier) + (wielder()->level() * provider().parryLvlModifier);
		}

		return parry;
	}

	float Item::blockPrecision() const {
		float block = provider().block;

		if(wielder() != NULL) {
			block += (wielder()->acc() * provider().blockAccModifier) + (wielder()->level() * provider().blockLvlModifier);
		}

		return block;
	}

	float Item::armorPiercing() const {
		float armorPierce = provider().armorPierce;

		if(wielder() != NULL) {
			armorPierce += (wielder()->acc() * provider().armorPierceAccModifier) + (wielder()->level() * provider().armorPierceLvlModifier);
		}

		return armorPierce;
	}

	float Item::criticalChance() const {
		float criticalChance = provider().crit;

		if(wielder() != NULL) {
			criticalChance -= (wielder()->acc() * provider().critAccModifier) - (wielder()->level() * provider().critLvlModifier);
		}

		return criticalChance;
	}

	float Item::damageReduction() const {
		return provider().armor;
	}

	Stat Item::statModification() const {
		return Stat(0.0f, 0.0f, provider().accModifier, provider().speModifier, 0.0f, 0.0f);
	}

	float Item::movementSpeed() const {
		float movementSpeed = provider().movementSpeed;

		if(wielder() != NULL) {
			movementSpeed -= (wielder()->str() * provider().movementSpeedStrModifier);
		}

		return movementSpeed;
	}

	float Item::sightRange() const {
		//! calculation
		return mProvider.sight;
	}

	float Item::attackSpeed() const {
		//! calculation
		return 0.0f;
	}

	float Item::parrySpeed() const {
		//! calculation
		return 0.0f;
	}

	float Item::staminaDrain() const {
		return mProvider.staminaDrain;
	}

	float Item::stagger() const {
		float stagger = provider().stagger;

		if(wielder() != NULL) {
			stagger += (wielder()->str() * provider().staggerStrModifier) + (wielder()->level() * provider().staggerLvlModifier);
		}

		return stagger;
	}

	float Item::staggerReduction() const {
		float reduction=mProvider.staggerReduction;

		return reduction;
	}

	float Item::overshootRange() const {
		//! calculation
		return 0.0f;
	}

	float Item::overshootMinRange() const {
		//! calculation
		return 0.0f;
	}

	float Item::projectileSpeed() const {
		//! calculation
		return 0.0f;
	}

	float Item::projectileSpeedCap() const {
		//! calculation
		return 0.0f;
	}

	void Item::setAnimation(Direction direction, std::string animationID, bool isLooping, float speed)
	{
		animator.setAnimation(direction, animationID, isLooping, speed);
	}

	void Item::setDirection(Direction direction, std::string animationID) {
		animator.setDirection(direction, animationID);
	}
}