#pragma once
#include "GameFramework/Character.h"
#include "PlayerSetupState.h"
#include "MiniMap.h"
#include "CharacterBase.generated.h"

UCLASS()
class ACharacterBase : public ACharacter
{
	GENERATED_BODY()
	friend class AItemBase;
public:
	ACharacterBase();

	virtual void BeginPlay() override;
	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
	virtual void Tick(float deltaTime) override;

	UFUNCTION(BlueprintCallable, Category = "Appearance")
	void EquipSkills(const TArray<UBaseSkillObject*>& skills);
	UFUNCTION(BlueprintCallable, Category = "Appearance")
	void EquipSkillsFromSkillTreeState(const struct FSkillTreeState& skState);
	UFUNCTION(NetMulticast, Reliable)
	void EquipItems(const TArray<TSubclassOf<class AItemBase>>& itemClasses);
	UFUNCTION(NetMulticast, Reliable)
	void EquipItem(TSubclassOf<class AItemBase> itemClasses);

	void SendInitialAppearance(APlayerController* pc);

	void Destroyed() override;

	UFUNCTION(BlueprintCallable, NetMulticast, Reliable, Category = "Appearance")
	void UnequipSkills(const TArray<UBaseSkillObject*>& skills);
	UFUNCTION(BlueprintCallable, NetMulticast, Reliable, Category = "Appearance")
	void ClearEquipment();
	UFUNCTION(BlueprintCallable, NetMulticast, Reliable, Category = "Appearance")
	void SetCustomizations(const FCharacterCustomization& cc);

	UFUNCTION(BlueprintCallable, Category = "Appearance")
	const TArray<class UBaseSkillObject*>& GetEquipedSkills() const;
	UFUNCTION(BlueprintCallable, Category = "Appearance")
	const TArray<class AItemBase*>& GetEquipedItems() const;
	UFUNCTION(BlueprintCallable, Category = "Appearance")
	TArray<TSubclassOf<class AItemBase>> GetEquipedItemClasses() const;
	UFUNCTION(BlueprintCallable, Category = "Appearance")
	const FCharacterCustomization& GetCharacterCustomization() const;

	UFUNCTION(BlueprintCallable, Category = "Team")
	int32 GetTeam() const;
	UFUNCTION(BlueprintCallable, Category = "Team")
	virtual void SetTeam(int32 team);

	// Tracking functions for effects on characters
	UFUNCTION(BlueprintCallable, Category = "Effect")
	void RegisterEffect(class AEffect* effect);
	UFUNCTION(BlueprintCallable, Category = "Effect")
	void UnRegisterEffect(class AEffect* effect);
	UFUNCTION(BlueprintCallable, Category = "Effect")
	TArray<class AEffect*> GetEffects();

	// The name of the player that controls this unit (Only for ghosts, players and illusions)
	UPROPERTY(BlueprintReadOnly, Replicated)
	FString playerName;

	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Vision")
	float visionRadius;

	MiniMap::MinimapHandle minimapHandle;

private:
	// Trigerred from RequestInitialAppearance send back to the client
	UFUNCTION(NetMulticast, Reliable)
	void m_ReceiveInitialAppearance(APlayerController* pc, const TArray<class UBaseSkillObject*>& itemClasses, const FCharacterCustomization& cc);
	// Internal usage EquipSkills to allow multiple ways to call this function from blueprints
	UFUNCTION(NetMulticast, Reliable)
	void m_EquipSkills(const TArray<UBaseSkillObject*>& skills);
	void m_OnItemAdded(AItemBase* item);
	void m_OnItemRemoved(AItemBase* item);

protected:
	UFUNCTION()
	virtual void m_OnRep_Team();

	UPROPERTY(ReplicatedUsing=m_OnRep_Team)
	int32 m_team;

	// Maps skills to the items it spawned
	TMultiMap<class UBaseSkillObject*, class AItemBase*> m_mappedItems;
	TArray<class UBaseSkillObject*> m_equipedSkills;
	UPROPERTY()
	TArray<class AItemBase*> m_items;

	TArray<class AEffect*> m_effects;
};
