/*
* Neural Tanks is a game created by Eddie O'Hagan that leverages Neural Networking
* to use for AI. This was created in Unreal Engine 4 which is developed by Epic Games.
* (Copyright Epic Games, Inc. All Rights Reserved.)
*
* Smart Tanks was originally developed by Mat Buckland in 2002 as an example
* on how Neural Networking can be used to train a set of minesweepers
* to collect mines. I (Eddie O'Hagan) updated this project in 2024 to use more
* Object Oriented Programming and modern practices. To see the original tutorial;
* visit <see href="http://www.ai-junkie.com/ann/evolved/nnt1.html">Neural Networking Tutorial</see>
* and <see href="http://www.ai-junkie.com/ga/intro/gat1.html">Genetic Algorithm Tutorial</see>
*/
#pragma once
#include <CoreMinimal.h>
#include "PhysicsTankPawn.h"
#include "../NeuralTanksGameInstance.h"
#include "../NeuralTanksGameMode.h"
#include "../SavingAndLoading/PlayerProgressionSaveGame.h"
#include "../Gameplay/Boombox.h"
#include "PlayerTankPawn.generated.h"

/// <summary>
/// The Player Tank is a Physics Tank that has the ability to be controlled by a player.
/// Input events are bound here along with controlling the boombox. It also has a camera.
/// </summary>
UCLASS(config=Game)
class APlayerTankPawn : public APhysicsTankPawn
{
	GENERATED_BODY()

protected:
	/// <summary>
	/// True if the mouse cursor is currently showing, false otherwise.
	/// </summary>
	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Camera")
	bool myIsCursorDisplayed;

	/// <summary>
	/// True if the player is currently using the top down level camera.
	/// </summary>
	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Camera")
	bool myIsLevelCameraInUse;

	/// <summary>
	/// The amount of money to give the player when picking up a TankAmmunition.
	/// </summary>
	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Camera")
	int myMoneyPerTankAmmunition;

	/// <summary>
	/// Base turn rate, in deg/sec. Other scaling may affect final turn rate.
	/// </summary>
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera")
	float myLookTurnRate;

	/// <summary>
	/// Base look up/down rate, in deg/sec. Other scaling may affect final rate.
	/// </summary>
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera")
	float myLookUpRate;

	/// <summary>
	/// Accumulated delta time from tick().
	/// </summary>
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Internal")
	float myTotalTime;

	/// <summary>
	/// A reference to the Neural Tanks game mode.
	/// </summary>
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "General")
	ANeuralTanksGameMode* myGameMode;

	/// <summary>
	/// A reference to the Neural Tanks game instance where saving/loading is primarily done.
	/// </summary>
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "General")
	UNeuralTanksGameInstance* myGameInstance;

	/// <summary>
	/// A pointer to the player's progression (exists in ANeuralTanksGameInstance).
	/// </summary>
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "General")
	UPlayerProgressionSaveGame* myPlayerProgression;

	/// <summary>
	/// The force feedback effect to use when the cannon fires.
	/// </summary>
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Vibration")
	UForceFeedbackEffect* myFireCannonForceFeedbackEffect;

	/// <summary>
	/// The audio sound effect to play when the player picks up an item.
	/// </summary>
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Audio")
	USoundBase* myTankPickUpItemSoundEffect;

	/// <summary>
	/// The audio sound effect to play when the player picks up an item.
	/// </summary>
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Audio")
	USoundBase* myPlayerWonRoundSoundEffect;

	/// <summary>
	/// The blueprint of the boombox, used to create the boombox object.
	/// </summary>
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Audio")
	TSubclassOf<UBoombox> myBoomboxBlueprint;

	/// <summary>
	/// Reference to this player's player controller.
	/// </summary>
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Internal")
	APlayerController* myPlayerController;

	/// <summary>
	/// The radio/boombox for playing music.
	/// </summary>
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Internal")
	UBoombox* myBoombox;

public:
	/// <summary>
	/// Default constructor.
	/// </summary>
	APlayerTankPawn();

	/// <summary>
	/// Called when this blueprint is first opened or initialized. This is equivalent to a 
	/// constructor but for Unreal Engine. 
	/// </summary>
	/// <param name="transform">The transform the actor was constructed at.</param>
	virtual void OnConstruction(const FTransform& transform) override;

	/// <summary>
	/// Called when this Player Tank first spawns into the world/level. Loads the save game,
	/// binds some events, and sets defaults for the tank if equipment was changed. Also
	/// applies equipment stats.
	/// </summary>
	virtual void BeginPlay() override;

	/// <summary>
	/// Registers the inputs (axis and actions) used by the player.
	/// </summary>
	/// <param name="playerInputComponent">The input component used to register bindings.</param>
	virtual void SetupPlayerInputComponent(UInputComponent* inputComponent) override;

	/// <summary>
	/// Called once per frame to repair the tank over time. This tank
	/// has it's armor replenished once every myTotalTime (in seconds)
	/// has passed.
	/// </summary>
	/// <param name="deltaTime">Time in milliseconds between frames.</param>
	virtual void Tick(float deltaTime) override;

	/// <summary>
	/// Plays vibration(s) on controller depending on the provided effect.
	/// </summary>
	/// <param name="theForceFeedbackEffect">The details of the vibration such as intensity and length.</param>
	virtual void PlayForceFeedback(UForceFeedbackEffect* theForceFeedbackEffect);

	/// <summary>
	/// Called when this tank collides/runs over an item on the ground.
	/// </summary>
	/// <param name="theItem">The item this tank collided with.</param>
	virtual void OnTankOverlappedItem(ATankItem* theItem) override;

	/// <summary>
	/// Called when this player has successfully hit an enemy tank.
	/// </summary>
	/// <param name="theHitTankPawn">The tank that the player hit.</param>
	virtual void OnSuccessfullyHitTank(ATankPawn* theHitTankPawn) override;

	/// <summary>
	/// Called when this tank has been hit with a projectile.
	/// </summary>
	/// <param name="theAttackingPawn">The tank that hit this tank/player.</param>
	/// <param name="damage">The amount of damage caused by the hit.</param>
	virtual void OnTankHit(ATankPawn* theAttackingPawn, float damage) override;
	
	/// <summary>
	/// Shows/Hides the mouse cursor in the game. The mouse cursor can be used for interacting
	/// with the boombox (if you are using mouse and keyboard).
	/// </summary>
	virtual void OnTogglePlayerCursor();

	/// <summary>
	/// Switches between the regular player camera, and the overhead
	/// drone camera that shows the whole map.
	/// </summary>
	virtual void OnTogglePlayerCamera();

	/// <summary>
	/// Shows/Hides the boombox in the player HUD.
	/// </summary>
	virtual void OnToggleBoombox();

	/// <summary>
	/// Increases the volume on the boombox/radio.
	/// </summary>
	virtual void OnIncreaseBoomboxVolume();

	/// <summary>
	/// Decreases the volume on the boombox/radio.
	/// </summary>
	virtual void OnDecreaseBoomboxVolume();

	/// <summary>
	/// Changes the boombox/radio to the next station (and starts playing that station).
	/// </summary>
	virtual void OnNextBoomboxStation();

	/// <summary>
	/// Changes the boombox/radio to the previous station (and starts playing that station).
	/// </summary>
	virtual void OnPreviousBoomboxStation();

	/// <summary>
	/// Called when this player presses the controller/keyboard button for firing the cannon.
	/// It spawns and fires the projectile and also plays vibration/force feedback if using
	/// a controller.
	/// </summary>
	void OnPlayerFireCannon(); //Needed because the registered function must be void.


	/// <summary>
	/// Called if/when a controller is connected or disconnected. We use this to
	/// pause the game if a controller is disconnected.
	/// </summary>
	/// <param name="isConnected">True if the controller was just connected, false if it was just disconnected.</param>
	/// <param name="userID">The unique identifier for the platform user associated with the device. This can be used to track specific users across multiple controllers.</param>
	/// <param name="userIndex">The unique identifier for the specific hardware input device. You can use this to distinguish between different controllers connected to the same machine (usually 0).</param>
	UFUNCTION()
	void OnControllerConnectionChanged(bool isConnected, int32 userID, int32 userIndex);

	/// <summary>
	/// Called by OnControllerConnectionChanged function to notify the blueprint side of the connection/disconnection.
	/// </summary>
	/// <param name="isConnected">True if the controller was just connected, false if it was just disconnected.</param>
	/// <param name="userID">The unique identifier for the platform user associated with the device. This can be used to track specific users across multiple controllers.</param>
	/// <param name="userIndex">The unique identifier for the specific hardware input device. You can use this to distinguish between different controllers connected to the same machine (usually 0).</param>
	UFUNCTION(BlueprintImplementableEvent, Category = "Events")
	void OnControllerConnectionChangedBlueprint(bool isConnected, int32 userID, int32 userIndex);

	/// <summary>
	/// Called when the level has been completed or the player has died.
	/// </summary>
	/// <param name="hasPlayerWon">true if the player has won the round, false if they died.</param>
	UFUNCTION()
	virtual void OnRoundEnded(bool hasPlayerWon);

	/// <summary>
	/// Rotates the tank turret (and cannon) left and right based on the player input.
	/// </summary>
	/// <param name="rate">The turn rate to use for moving the turret (and cannon).</param>
	void TurnTurret(float rate);

	/// <summary>
	/// Moves the tank cannon up and down based on the player input.
	/// </summary>
	/// <param name="rate">The rate to use for moving the cannon.</param>
	void PitchCannon(float rate);

	/// <summary>
	/// Creates a new save and saves the current game progress without having to go to the save menu.
	/// </summary>
	void QuickSaveGame();

	/// <summary>
	/// Returns the current amount of health (HP) the player tank has.
	/// </summary>
	/// <returns>The current amount of health (HP) the player tank has.</returns>
	float GetCurrentHealth();
};

