// Project Lab - NHTV Igad

#pragma once

#include "DealDamageProxy.h"
#include <list>
#include "AbilityInfo.h"
#include "Modifier.generated.h"

class ModifierManager
{
public:
	ModifierManager(class ANetworkCharacter* character);
	~ModifierManager();

	void ClearModifiers(bool shouldCallEnd = true);
	void Tick(float DeltaSeconds);

	class AModifier* AddModifier(TSubclassOf<class AModifier> modifierClass, float duration);
	class AModifier* AddModifier(AModifier* modifierInstance);
	TArray<class AModifier*>  GetModifiersOfClass(TSubclassOf<class AModifier> modifierClass);
	void RecalculateCharacter();
	void BroadcastManaDrainFailed();

private:
	void m_Reset();

	friend class ANetworkCharacter;
	TArray<class AModifier*> m_modifiers;
	class ANetworkCharacter* m_character;
};

UCLASS()
class UNREALPROJECT_API AModifier : public ADealDamageProxy
{
	GENERATED_BODY()
	
	friend class ADefaultPlayerController;
	friend class ModifierManager;
	friend class ANetworkCharacter;
	friend class AOnDamageModifier;

public:	
	AModifier();
	virtual void Tick(float DeltaSeconds) override final;
	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;

	virtual void ModifierTick();
	virtual void ModifierStart();
	virtual void ModifierEnd();
	virtual bool OnDamage(int32& damage, ANetworkCharacter* damageDealer);
	virtual bool OnDealDamage(int32& damage, ANetworkCharacter* damageTaker);
	virtual void OnStandardAttack(ANetworkCharacter* character);
	virtual void AfterDamage(int32 damage);

	UFUNCTION(BlueprintCallable, Category = "modifiers")
	virtual bool ShouldBeRemoved() const;
	virtual void ModifyCharacter();
	UFUNCTION(BlueprintCallable, Category = "modifiers")
	void ForceDestroy();

	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "modifiers", meta=(ExposeOnSpawn))
	float lifeTime;
	UPROPERTY()
	ANetworkCharacter* target;
	UPROPERTY(EditDefaultsOnly, Category = "modifiers")
	int32 ticksPerSecond;
	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "modifiers", meta = (ExposeOnSpawn))
	int32 priority;

	DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnManaDrainFailed);

	UPROPERTY(BlueprintAssignable, Category = "Mana Drain")
		FOnManaDrainFailed onManaDrainFailed;

	bool operator < (const AModifier&) const;
	bool operator > (const AModifier&) const;
protected:
	enum EffectType
	{
		additive = 0,
		multiplicative
	};
	float m_MultiplyEffect(float value, EffectType effectType, bool positive);

	// Modification Functions
	void m_AddMaxMana(int32 maxMana);
	void m_MultiplyManaRegenMultiplier(float manaRegenMultiplier);
	void m_AddBlockedMana(int32 blockedMana);
	void m_AddDamageMultiplier(float multiplier);
	void m_AddIgnoreArmor(float normalizedPercentage);
	void m_AddArmor(float armor);
	void m_MultiplyArmor(float armor);
	void m_MultiplyDamageTakenMultiplier(float multiplier);
	void m_AddMaxHealth(int32 health);
	void m_AddMovementSpeedMultiplier(float multiplier);
	void m_AddAttackSpeed(float amount);
	void m_AddAttackSpeedMultiplier(float multiplier);
	void m_AddCooldownReduction(float amount);
	void m_AddCooldownReductionMultiplier(float multiplier);
	void m_AddStunnedState();
	void m_AddSilencedState();
	void m_RemoveSilencedState();
	void m_MultiplyAttackDamage(float damageMultiplier);
	void m_AddMagicDamage(float damageMultiplier);
	void m_MultiplyManaUsageMultiplier(float manaUsageMultiplier);
	void m_MultiplyNegativeEffectMultiplier(float effectMultiplier);
	void m_MultiplyPositiveEffectMultiplier(float effectMultiplier);
	void m_MultiplyMagicDamageMultiplier(float effectMultiplier);
	void m_addChannelMovementSpeedMultiplier(float channelMovementSpeedMultiplier);
	float m_tickRate;

private:
	void m_Start();
	void m_Init(class ANetworkCharacter* character, float duration);

	bool m_forceDestroy;
	int m_debugWarning;
	bool m_started;
	float m_tickTimer;
	bool m_dontDestroy;
};