// Project Sword & Gun Copyright © 2021 Kevin Poretti

#pragma once

#include "CoreMinimal.h"

#include "Characters/SNGProtagonist.h"
#include "GameFramework/PlayerController.h"
#include "SNGPlayerController.generated.h"

UENUM()
enum class ERawInputs : uint8
{
	NEUTRAL,
	BACK,
	FORWARD,
	LEFT,
	RIGHT,
	ATTACK,
	DASH,
};

USTRUCT()
struct FInputAction
{
	GENERATED_BODY()

	FName Name;
	
	EActionState State;

	bool IsConsumed;
	
	FInputAction()
		: Name(NAME_None), State(EActionState::AS_Released), IsConsumed(false)
	{
		
	}
};

USTRUCT()
struct FBufferedInput
{
	GENERATED_BODY()

	float TimeAdded;
	
	FVector2D Stick;

	// what cardinal direction is being pressed this frame
	ERawInputs Direction;
	
	TArray<FInputAction> Actions;
	
	FBufferedInput()
		: TimeAdded(0.0f)
	{
		
	}
};

USTRUCT()
struct FSpecialCommand
{
	GENERATED_BODY()

	UPROPERTY(EditDefaultsOnly)
	FName Name;

	// How much time can pass before the command resets
	UPROPERTY(EditDefaultsOnly)
	float TimeToReset;
	
	UPROPERTY(EditDefaultsOnly)
	TArray<ERawInputs> Commands;

	int CurrCommandIdx;

	float CurrTime;
};

/**
 * 
 */
UCLASS()
class SWORDNGUN_API ASNGPlayerController : public APlayerController
{
	GENERATED_BODY()

public:
	ASNGPlayerController();
	
protected:
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Properties")
	float MaxInputLifetime;

	UPROPERTY(EditDefaultsOnly, Category="Special Commands")
	TArray<FSpecialCommand> SpecialCommands;

	virtual void OnPossess(APawn* aPawn) override;

	virtual void OnUnPossess() override;
	
	void SetupInputs();

	void RegisterAction(FName ActionName, FName CommandName);
	
	//void BindActionToCharacterCommand(FName ActionName, FName CommandName);
	void BindAddInputAction(FName ActionName, EActionState ActionState, EInputEvent InputEvent);
	
	void AddInputActionToBuffer(FName ActionName, EActionState State);
	
	// NOTE(kevin): We want to decouple the controller from having to have a reference to its pawn
	// We only want to send commands to the pawn based off of inputs
	// This is only temporary until we get something up and running
	ASNGProtagonist* Protagonist;

	float BaseTurnRate;
	
	float BaseLookUpRate;
	
	void TurnRate(float Rate);
	
	void LookUpRate(float Rate);
	
	virtual void Tick(float DeltaSeconds) override;
	
private:	
	TArray<FBufferedInput> Buffer;

	FBufferedInput CurrInput;

	TMap<FName, FName> ActionToCharacterCommand;
	
	void PushCharacterCommandToPawn(FName Command, EActionState ActionState);

	void ProcessInputFrame(FBufferedInput& InputFrame);
	//void ProcessActions(TArray<FInputAction>& Actions);
	
	// Converts a world input direction into a cardinal direction.
	// Cardinal direction determined by where the input direction is pointing relative to where the character
	// and the camera is facing.
	//ERawInputs WorldInputDirectionToCardinalDirection(FVector WorldInputDirection);
	
	FVector GetInputAsWorldDirection(float ForwardAxisValue, float RightAxisValue);
};
