// Gravity Stomp Copyright Kevin Poretti

#pragma once

// GS includes
#include "Player/GSPlayerController.h"
#include "Player/GSPlayerState.h"

// UE includes
#include "CoreMinimal.h"
#include "GameFramework/GameMode.h"

#include "GSGameModeBase.generated.h"

/**
 *	Game mode for a team deathmatch/free for all game mode
 */
UCLASS(minimalapi)
class AGSGameModeBase : public AGameMode
{
	GENERATED_BODY()

public:
	AGSGameModeBase();

    /**
	 *	Sets up default timer
	 */
	virtual void PreInitializeComponents() override;

	/**
	 *	Initialize the game. This is called before actors' PreInitializeComponents.
	 *
	 */
	virtual void InitGame(const FString& MapName, const FString& Options, FString& ErrorMessage) override;

	/**
	 *	Initialize the game state. Sets the number of teams based on this game mode's settings.
	 */
	virtual void InitGameState() override;

	/**
	 *	Accept or reject a player attempting to join the server.  Fails login if you set the ErrorMessage to a non-empty string.
	 */
	virtual void PreLogin(const FString& Options, const FString& Address, const FUniqueNetIdRepl& UniqueId, FString& ErrorMessage) override;

	/**
	 *	Picks a player team and informs them to start if the match is in progress
	 */
	virtual void PostLogin(APlayerController* NewPlayer) override;

	/**
	 *	Tries to spawn the player's pawn
	 */
	virtual void RestartPlayer(AController* NewPlayer) override;

	/**
	 *	Choose a random spawn
	 */
	virtual bool ShouldSpawnAtStartSpot(AController* Player) override;

	/**
	 *	Checks if one player can damage another. For example, players on the same team should not be able to damage one another.
	 */
    virtual bool CanDamagePlayer(AGSPlayerController* Damager, AGSPlayerController* Victim);

	/**
	 *	Decides on a team for a player based on current player distribution
	 */
	virtual void PickTeam(AGSPlayerState* PlayerState);

	/**
	 *	Handles updating score and informing appropriate clients when one player kills another
	 */
	UFUNCTION(BlueprintCallable)
	virtual void OnPlayerKilled(AGSPlayerController* Killer, AGSPlayerController* Victim);

	/**
	 *	Decides which team wins and then informs players the match has ended and if they won or not
	 */
	void FinishMatch();

	UFUNCTION(BlueprintImplementableEvent)
	void OnMatchFinished(int32 WinningTeamIdx);

	/**
	 *	If the match is in the post match state calling this restarts the game 
	 */
	UFUNCTION(BlueprintCallable)
	virtual void OnMatchRestartRequest();

	virtual void HandleStartingNewPlayer_Implementation(APlayerController* NewPlayer) override;

	/**
	 *	Sets up match warmup timer
	 */
	virtual void HandleMatchIsWaitingToStart() override;

	/**
	 *	Sets up match round timer
	 */
	virtual void HandleMatchHasStarted() override;

	/**
	 *	Notifies players
	 */
	virtual void RestartGame() override;

	/**
	 *	Function that acts as the game mode "tick" and does match state transition logic
	 */
	virtual void DefaultTimer();

protected:
	// Maximum number of teams allowed in this gamemode
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category=Settings, meta = (ClampMin = 0))
	int32 MaxNumTeams;

	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category=Settings, meta = (ClampMin = 0))
	int32 ScoreLimit;

	// time in between rounds, in seconds
    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category=Settings, meta = (ClampMin = 0))
	float TimeBetweenRounds;

	// duration of a round, in seconds
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category=Settings, meta = (ClampMin = 0))
	float RoundTime;

	// duration of the pre-match/warmup period, in seconds
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category=Settings, meta = (ClampMin = 0))
	float WarmupTime;

	FTimerHandle TimerHandle_DefaultTimer; 
};



