// Project Lab - NHTV Igad

#pragma once

#include "GameFramework/PlayerController.h"
#include "IngameSkillTree.h"
#include "PlayerControllerBase.h"
#include "PlayerSetupState.h"
#include "DefaultPlayerController.generated.h"

UCLASS()
class UNREALPROJECT_API ADefaultPlayerController : public APlayerControllerBase
{
	GENERATED_BODY()

public:
	ADefaultPlayerController(const FObjectInitializer& init);
	virtual void BeginPlay() override;
	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
	virtual void Destroyed() override;
	virtual void SetupInputComponent() override;
	virtual void Tick(float DeltaSeconds) override;

	virtual void Possess(APawn* aPawn) override;

	virtual void SeamlessTravelFrom(class APlayerController* OldPC) override;

	// This is used to handle the player being destroyed
	virtual void PawnPendingDestroy(APawn* inPawn) override;

	void UpdatePlayerPosition(const FVector& location, const FRotator& rotator);

	// Called when the possesed pawn is replicated
	virtual void OnRep_Pawn() override;

	UFUNCTION(Reliable, Client)
	void OnLevelUpClient(const TArray<FIngameSkillTreeSkill>& updatedSkills, const TArray<FIngameSkillTreeSkill>& oldSkills);

	// Only called on server, called to learn skills on the currently owned pawn
	void LearnSkillsForLevel();

	bool GetAbilityButtonLocation(class UAbilityInfo* ability, int32& slot, bool& isAlt);
	int32 GetCurrentAbilityLevel(class UAbilityInfo* ability);

	void ToggleSkillTree();
	void ToggleMenu();
	UFUNCTION(BlueprintCallable, Category="UI")
	void OnHideUI();
	void OnCharacterCreated(class ANetworkCharacter* character);
	void OnCharacterDestroyed(class ANetworkCharacter* character);
	const TArray<class UAbilityInfo*>& GetAbilities(APawn* targetPawn = nullptr);

	bool HasGameFocus();

	// Ability cast
	void CastAbility(int32 index);
	// Called for hold abilities to turn them off
	void UnCastAbility(int32 index);

	UAbilityInfo* GetMappedAbility(int32 index);

	// Ability Button-Down events
	void CastAbility0();
	void CastAbility1();
	void CastAbility2();
	void CastAbility3();
	void CastAbility4();
	void CastAbility5();
	void CastAbility6();
	void CastAbility7();
	void CastAbility8();
	// Ability Button-Up events
	void UnCastAbility0();
	void UnCastAbility1();
	void UnCastAbility2();
	void UnCastAbility3();
	void UnCastAbility4();
	void UnCastAbility5();
	void UnCastAbility6();
	void UnCastAbility7();
	void UnCastAbility8();

	void CoopModifierOn();
	void CoopModifierOff();
	void MoveForward(float Value);
	void MoveRight(float Value);
	void TurnAtRate(float Rate);
	void LookUp(float Rate);
	void LookUpAtRate(float Rate);

	void RightMouseDown();
	void RightMouseUp();
	void LeftMouseDown();
	void ToggleSwitch();
	void LeftMouseUp();
	void HoldDown();
	void HoldUp();

	void SpawnCharacterForClient();
	void SpawnCharacterForClient(const FVector& location, const FRotator& rotation);

	UFUNCTION(Reliable, Server, WithValidation)
	void LearnSkillOnServer(class UBaseSkillObject* object);
	UFUNCTION( Reliable, Server, WithValidation )
	void UnlearnSkillOnServer(class UBaseSkillObject* object);

	void OnLearnSkill(class UBaseSkillObject* object);
	void OnUnlearnSkill(class UBaseSkillObject* object);

	TArray<class UBaseSkillObject*>& GetSkills();

	void UpdateLevel();

	UFUNCTION(Exec)
	void SetLevel(int32 level);
	UFUNCTION(Reliable, Server, WithValidation)
	void SetLevel_Server(int32 level);

	UFUNCTION(Exec)
	void Suicide();
	UFUNCTION(Reliable, Server, WithValidation)
	void Suicide_Server();

	UFUNCTION(Exec)
	void TestWinGame(int32 team);

	UFUNCTION(Client, Reliable)
	void SpawnCombatText(const FVector& position, const FString& string, const FLinearColor& color);
	UFUNCTION(Client, Reliable)
	void SpawnArcingCombatText(const FVector& position, const FString& string, const FLinearColor& color);

	// Called when setupState is replicated
	UFUNCTION()
	virtual void OnRep_Setup() override;

	UFUNCTION(BlueprintCallable, Category="State")
	FCharacterClassProperty GetCharacterClassProperties() const;

	UFUNCTION(BlueprintCallable, Category = "State")
	class UIngameHUD* GetHUD();

	// Player location history
	struct Location
	{
		Location(const FVector& location, const FRotator& rotation) : location(location), rotation(rotation) {}
		FVector location;
		FRotator rotation;
	};
	TArray<Location> playerLocationHistory;

	UPROPERTY(BlueprintReadOnly, EditAnywhere)
	class UCharacterClassPropertySet* characterClassProperties;

	METRICS_EXPR(Metrics::PlayerHandle* metricsHandle);

protected:
	// Called when the player possesed pawn has changed, on client or server(players)
	virtual void m_OnPawnChanged();

private:
	void m_UpdateUI();
	void m_CreateIngameSkilltree();
	void m_StartBasicAttack();
	void m_TickBasicAttack();
	void m_StopBasicAttack();

	// To check editor play
	bool m_seamlessTravelDone;

	// Selected class properties the player chose for his character build
	FCharacterClassProperty m_classProperties;

	UPROPERTY(Replicated)
	TArray<class UBaseSkillObject*> m_skills;

	// Check for recent mouse/controller usage
	FVector2D m_mouseLast;

	FVector m_holdDirection;

	bool m_rightMouseDown;
	bool m_coopModifier;
	bool m_holdPosition;
	bool m_skillTreeInitialized;
	bool m_usingBasicAttack;

	TArray<class UAbilityInfo*> m_mainSkillMapping;
	TArray<class UAbilityInfo*> m_altSkillMapping;
	TSet<class UAbilityInfo*> m_learnedAbilities;

	TArray<FIngameSkillTreeSkill> m_alreadyLearnedSkills;

	uint32 m_framesSinceMenuFocus;
	UPROPERTY()
	class UMenuScreen* m_ingameMenu;
	UPROPERTY()
	class UMenuPanel* m_ingameMenuPanel;
	UPROPERTY()
	class UIngameHUD* m_hud;
	UPROPERTY()
	class UUserWidget* m_respawnWidget;
	UPROPERTY()
	class USkillTreeWidget* m_skillTreeWidget;
	friend class ABuff;

	UPROPERTY()
	class AIngameSkillTree* m_skillTree;

	UPROPERTY(Replicated)
	class ADefaultPlayer* m_defaultPlayer;

};
