// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Target.generated.h"

/**
* Defines the states a target can be in.
*/
UENUM(BlueprintType)
enum class ETargetState : uint8
{
	Moving		UMETA(DisplayName = "Moving"),
	Flipping	UMETA(DisplayName = "Flipping"),
	BeingShot	UMETA(DisplayName = "Being Shot")
};

/**
* Defines the different types of a target's face.
*/
UENUM(BlueprintType)
enum class EFaceType : uint8
{
	Angel	UMETA(DisplayName = "Angel"),
	Devil	UMETA(DisplayName = "Devil"),
	Joker	UMETA(DisplayName = "Joker")
};

/**
* Defines a target which moves inside the carnival stand.
* The target can be shot of flipped by the player.
*/
UCLASS()
class GAMEJAMTEMPLATE_API ATarget : public AActor
{
	GENERATED_BODY()
	
public:

	ATarget();

	void Tick(float DeltaTime) override;

	/**
	* Gets the face that's currently pointing at the player.
	* @return The face currently pointing at the player.
	*/
	EFaceType GetCurrentFace();

	/**
	* Sets the target's spawner.
	* @param NewTargetSpawner The target's spawner.
	*/
	void SetTargetSpawner(class ATargetSpawner* NewTargetSpawner);

	/**
	* Sets the target's lane.
	* @param NewLane The target's lane.
	*/
	void SetLane(class ALane* NewLane);

	/**
	* Sets the faces of the target.
	* @param NewHeads The face of the first side of the target.
	* @param NewTails The face of the second side of the target.
	*/
	void SetFaces(EFaceType NewHeads, EFaceType NewTails);

	/**
	* Sets the parameters for moving the target.
	* @param NewMovementSpeed The target's new movement speed.
	* @param NewMovementDirection The target's new movement direction.
	*/
	void SetMovementParameters(float NewMovementSpeed, FVector NewMovementDirection);

	/**
	* Shoots the target.
	* @param BlastRadius The radius of the blast. Transfers effect to targets in radius.
	* @param bCountPoints If true, count the points for this shot.
	*/
	void Shoot(float BlastRadius = 0.0f, bool bCountPoints = true);

	/**
	* Flips the target.
	* @param bFlipRight Indicates if the target should flip to the right.
	* @param BlastRadius The radius of the blast. Transfers effect to targets in radius.
	*/
	void Flip(bool bFlipRight, float BlastRadius = 0.0f);

protected:

	void BeginPlay() override;

private:

	// The name of the object fetched by the UObjectBaseUtility::GetName method
	const FString ObjectName;

	// The paper flipbook component holding the sprites.
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components", meta = (AllowPrivateAccess = "true"))
	class UPaperFlipbookComponent* PaperFlipbook;

	// A static mesh used to detect hits performed by the player.
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components", meta = (AllowPrivateAccess = "true"))
	class UStaticMeshComponent* HitComponent;

	// The animations of the target moving based on its displayed face.
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Animations", meta = (AllowPrivateAccess = "true"))
	TMap<EFaceType, class UPaperFlipbook*> MovingAnimations;

	// The animations of the target flipping towards the right.
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Animations", meta = (AllowPrivateAccess = "true"))
	TMap<EFaceType, class UPaperFlipbook*> FlippingRightAnimations;

	// The animations of the target flipping towards the left.
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Animations", meta = (AllowPrivateAccess = "true"))
	TMap<EFaceType, class UPaperFlipbook*> FlippingLeftAnimations;

	// The animations of the target being shot.
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Animations", meta = (AllowPrivateAccess = "true"))
	TMap<EFaceType, class UPaperFlipbook*> BeingShotAnimations;

	// The sound of the target being shot.
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Sounds", meta = (AllowPrivateAccess = "true"))
	class USoundCue* TargetShotSound;

	// The sound of the target being flipped.
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Sounds", meta = (AllowPrivateAccess = "true"))
	class USoundCue* TargetFlippedSound;

	// A reference to the default game mode.
	class AJamGameMode* JamGameMode;

	// A reference to the sound manager.
	class USoundManager* SoundManager;

	// A reference to the game's level handler.
	class ALevelHandler* LevelHandler;

	// A reference to the target's spawner.
	class ATargetSpawner* TargetSpawner;

	// A reference to the target's lane.
	class ALane* Lane;

	// The state the target was previously in.
	ETargetState PreviousState;

	// The state the target is currently in.
	ETargetState CurrentState;

	// The type of face showed on the target's first side.
	EFaceType Heads;

	// The type of face showed on the target's second side.
	EFaceType Tails;

	// Indicates if the heads side of the target is facing the player.
	bool bIsFacingHeads;

	// The speed at which the target moves.
	float MovementSpeed;

	// The direction the target is moving in.
	FVector MovementDirection;

	/**
	* Change the target's state.
	* @param NewState The target's new state.
	*/
	void ChangeState(ETargetState NewState);

	/**
	* Play a new animation in the paper flipbook component.
	* @param Animation The new animation to play.
	* @param bLoop True if the animation should loop.
	*/
	void PlayAnimation(class UPaperFlipbook* Animation, bool bLoop);

	/**
	* Gets the current animation based on the target's displayed face.
	* @return A pointer to the corresponding animation.
	*/
	class UPaperFlipbook* GetAnimation(const TMap<EFaceType, class UPaperFlipbook*>& Animations);

	/**
	* Gets the current moving animation based on the target's displayed face.
	* @return A pointer to the corresponding moving animation.
	*/
	class UPaperFlipbook* GetMovingAnimation();

	/**
	* Gets the current flipping animation based on the target's displayed face.
	* @param bFlipRight Indicates if the target should flip to the right.
	* @return A pointer to the corresponding flipping animation.
	*/
	class UPaperFlipbook* GetFlippingAnimation(bool bFlipRight);

	/**
	* Gets the current animation for being shot based on the target's displayed face.
	* @return A pointer to the corresponding being shot animation.
	*/
	class UPaperFlipbook* GetBeingShotAnimation();

	/**
	* Moves the target along its lane.
	* @param DeltaTime The elapsed time between the previous two ticks.
	*/
	void Move(float DeltaTime);

	/**
	* Updates the player's score based on the targets they shot.
	* @param NumberOfAngels The number of angels the player shot.
	* @param NumberOfDevils The number of devils the player shot.
	*/
	void UpdateScore(int NumberOfAngels, int NumberOfDevils);

};
