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

#pragma once

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

/**
* A structure which contains data about a single round of the game.
*/
USTRUCT(BlueprintType)
struct FGameRound
{
	GENERATED_USTRUCT_BODY()

	// Indicates if this round has its own tutorial.
	UPROPERTY(EditAnywhere, BlueprintReadOnly)
	bool bHasTutorial;

	// The text of this round's tutorial.
	UPROPERTY(EditAnywhere, BlueprintReadOnly)
	FString TutorialText;

	// The duration of the round.
	UPROPERTY(EditAnywhere, BlueprintReadOnly)
	float Duration;

	// The number of lanes to use.
	UPROPERTY(EditAnywhere, BlueprintReadOnly)
	int NumberOfLanes;

	// The time that elapses between two targets being spawned.
	UPROPERTY(EditAnywhere, BlueprintReadOnly)
	float SpawningInterval;

	// The amount of time the spawning interval can flux.
	UPROPERTY(EditAnywhere, BlueprintReadOnly)
	float DeltaInterval;

	// The movement speed of the spawned targets.
	UPROPERTY(EditAnywhere, BlueprintReadOnly)
	float TargetMovementSpeed;

	// Indicates if the blue ammo is enabled.
	UPROPERTY(EditAnywhere, BlueprintReadOnly)
	bool bIsBlueAmmoEnabled;

	// Indicates if the spread for red ammo is enabled.
	UPROPERTY(EditAnywhere, BlueprintReadOnly)
	bool bIsRedSpreadEnabled;

	// Indicates if the spread for blue ammo is enabled.
	UPROPERTY(EditAnywhere, BlueprintReadOnly)
	bool bIsBlueSpreadEnabled;

};

/**
* A level handler which is responsible for starting and stopping the level.
*/
UCLASS()
class GAMEJAMTEMPLATE_API ALevelHandler : public AActor
{
	GENERATED_BODY()
	
public:

	ALevelHandler();

	void Tick(float DeltaTime) override;

	/**
	* Checks if a round is being played right now.
	* @return True if a round is being played, else false.
	*/
	UFUNCTION(BlueprintCallable)
	bool IsRoundPlaying();

	/**
	* Checks if the game is over.
	* @return True if the game is over, else false.
	*/
	UFUNCTION(BlueprintCallable)
	bool IsGameOver();

	/**
	* Checks if tutorial for the current round if being shown.
	* @return True if the tutorial is being shown, else false.
	*/
	UFUNCTION(BlueprintCallable)
	bool IsShowingTutorial();

	/**
	* Checks if the blue ammo for the current round is enabled.
	* @return True if the blue ammo is enabled, else false.
	*/
	UFUNCTION(BlueprintCallable)
	bool IsBlueAmmoEnabled();

	/**
	* Checks if the red spread for the current round is enabled.
	* @return True if the red spread is enabled, else false.
	*/
	UFUNCTION(BlueprintCallable)
	bool IsRedSpreadEnabled();

	/**
	* Checks if the blue spread for the current round is enabled.
	* @return True if the blue spread is enabled, else false.
	*/
	UFUNCTION(BlueprintCallable)
	bool IsBlueSpreadEnabled();

	/**
	* Checks if the curtain is down across the level.
	* @return True if the curtain is down, else false.
	*/
	UFUNCTION(BlueprintCallable)
	bool IsCurtainDown();

	/**
	* Checks if the curtain is opening.
	* @return True if the curtain is opening, else false.
	*/
	UFUNCTION(BlueprintCallable)
	bool IsCurtainOpening();

	/**
	* Get the remaining time for the current round.
	* Ceil the number. Return 0 if game isn't playing.
	* @return The number of seconds left for the current round.
	*/
	UFUNCTION(BlueprintCallable)
	int GetRemainingTime();

	/**
	* Gets the current score the player has achieved.
	* @return The player's current score.
	*/
	UFUNCTION(BlueprintCallable)
	int GetCurrentScore();

	/**
	* Gets the number of the player has committed in this round.
	* @return The number of the player has committed.
	*/
	UFUNCTION(BlueprintCallable)
	int GetNumberOfPenalties();

	/**
	* Get the tutorial text of the current round.
	* @return The text of the tutorial.
	*/
	UFUNCTION(BlueprintCallable)
	FString GetTutorialText();

	/**
	* Resets the game and allows the player to restart from the beginning.
	*/
	UFUNCTION(BlueprintCallable)
	void Reset();

	/**
	* Gets the next round and starts it.
	* If the round has a tutorial, display the tutorial.
	* Else, play the round immediately.
	*/
	UFUNCTION(BlueprintCallable)
	void StartRound();

	/**
	* Plays the current round.
	*/
	UFUNCTION(BlueprintCallable)
	void PlayRound();

	/**
	* Stops a round.
	*/
	UFUNCTION(BlueprintCallable)
	void StopRound();

	/**
	* Open the curtains over the level.
	*/
	UFUNCTION(BlueprintCallable)
	void OpenCurtain();

	/**
	* Adds another point to the total score.
	* @param NumberOfDevils The number of devils the player shot.
	* @param bApplyCombo Apply a combo boost if no angels were shot.
	*/
	void AddPoint(int NumberOfDevils, bool bApplyCombo);

	/**
	* Adds another penalty to the total score.
	* @param NumberOfAngels The number of angels the player shot.
	*/
	void AddPenalty(int NumberOfAngels);

protected:

	void BeginPlay() override;

private:

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

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

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

	// The animation of the curtain closing.
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Animations", meta = (AllowPrivateAccess = "true"))
	class UPaperFlipbook* CurtainCloseAnimation;

	// The animation of the curtain opening.
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Animations", meta = (AllowPrivateAccess = "true"))
	class UPaperFlipbook* CurtainOpenAnimation;

	// The sound of the curtain closing.
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Sounds", meta = (AllowPrivateAccess = "true"))
	class USoundCue* CurtainCloseSound;

	// The sound of the curtain opening.
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Sounds", meta = (AllowPrivateAccess = "true"))
	class USoundCue* CurtainOpenSound;

	// The list of levels present in the game.
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Rounds", meta = (AllowPrivateAccess = "true"))
	TArray<FGameRound> Rounds;

	// The current round being played.
	FGameRound CurrentRound;

	// The target spawner present in the level.
	class ATargetSpawner* TargetSpawner;

	// Indicates if a round is currently playing.
	bool bIsRoundPlaying;

	// Indicates if the game is over either if the player completed
	// all of the levels or committed the maximum amount of penalties.
	bool bIsGameOver;

	// Indicates if the current round's tutorial is being displayed.
	bool bIsShowingTutorial;

	// Indicates if the curtains are currently down.
	bool bIsCurtainDown;

	// Indicates if the curtain is currently closing.
	bool bIsCurtainClosing;

	// Indicates if the curtain is currently opening.
	bool bIsCurtainOpening;

	// The number of the next round that should be automatically played.
	int NextRound;

	// The amount of time that elapsed since a round started.
	float ElapsedTime;

	// The current score the player has achieved.
	int CurrentScore;

	// The maximum amount of penalties the player can commit in a round before losing the game.
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Variables", meta = (AllowPrivateAccess = "true"))
	int MaxNumberOfPenalties;

	// The number of penalties the player has committed in the current round.
	int NumberOfPenalties;

	/**
	* Gets the specified round.
	* @return The specified round.
	*/
	FGameRound GetRound(int RoundNumber);

	/**
	* Shows the tutorial of the current round.
	*/
	void ShowTutorial();

	/**
	* Hides the tutorial of the current round.
	*/
	void HideTutorial();

	/**
	* Close the curtains over the level.
	*/
	void CloseCurtain();

	// Pointer to the Ammo Spawner
	class AAmmoSpawner* LevelAmmoSpawner;

};
