// Project Lab - NHTV Igad

#include "UnrealProject.h"
#include "KingOfTheHillGameMode.h"
#include "DefaultGameState.h"
#include "DefaultGameState.h"
#include "DefaultGameInstance.h"
#include "PlayerSpawn.h"
#include "NetworkPlayer.h"
#include "CreatureSpawn.h"
#include "DefaultPlayer.h"
#include "DefaultPlayerState.h"
#include "KOTHPlayerController.h"
#include "KOTHGameState.h"
#include "KOTHBossSpawner.h"

AKingOfTheHillGameMode::AKingOfTheHillGameMode()
{
	PrimaryActorTick.bCanEverTick = true;

	// Lobby system starts the match
	bDelayedStart = true;

	PlayerControllerClass = AKOTHPlayerController::StaticClass();
	DefaultPawnClass = ConstructorHelpers::FClassFinder<APawn>(TEXT("/Game/Assets/Blueprints/BP_DefaultPlayer")).Class;
	SpectatorClass = ConstructorHelpers::FClassFinder<ASpectatorPawn>(TEXT("/Game/Assets/Blueprints/BP_SpectatorPawn")).Class;

	GameStateClass = AKOTHGameState::StaticClass();
	PlayerStateClass = ADefaultPlayerState::StaticClass();
	maxGameScore = 60.0f;
	m_currentTeamWithHill = -1;
}
void AKingOfTheHillGameMode::InitGame(const FString& MapName, const FString& Options, FString& ErrorMessage)
{
	Super::InitGame(MapName, Options, ErrorMessage);

	auto spawnerIt = TActorIterator<AKOTHBossSpawner>(GetWorld(), AKOTHBossSpawner::StaticClass());
	if(!spawnerIt)
	{
		GERROR("No instance of AKOTHBossSpawner found in the level, you need one when using the KOTH game mode!");
	}
	else
	{
		bossSpawner = *spawnerIt;
	}
}
void AKingOfTheHillGameMode::HandleMatchHasStarted()
{
	AKOTHGameState* gameState = GetGameState<AKOTHGameState>();
	gameState->maxGameScore = maxGameScore;
	TArray<int32> teamsize = gameState->GetTeamSizes();
	for (int i = 0; i < teamsize.Num(); i++)
	{
		FKOTHTeamState state;
		state.active = 0;
		state.score = 0.0f;
		state.maxScore = maxGameScore;
		state.containsMembers = teamsize[i] > 0;
		gameState->kothTeams.Add(state);
	}

	Super::HandleMatchHasStarted();
}
void AKingOfTheHillGameMode::Tick(float deltaTime)
{
	Super::Tick(deltaTime);

	AKOTHGameState* gameState = GetGameState<AKOTHGameState>();
	for (int i = 0; i < gameState->kothTeams.Num(); i++)
	{
		FKOTHTeamState& state = gameState->kothTeams[i];
		if(state.score >= maxGameScore)
		{
			// Check overtime condition
			if(bossSpawner)
			{
				// Check overtime conditions / convert index to team index [0-4] -> [1-5]
				if(!bossSpawner->IsContested(i + 1) && bossSpawner->IsBossAlive())
				{
					WinGame(i);
				}
				else
				{
					gameState->overtime = true;
				}
			}
		}

		if(state.active > 0)
		{
			state.active--;
		}
	}

}
void AKingOfTheHillGameMode::WinGame(int team)
{
	TArray<class ANetworkCharacter*> players(m_players);

	// Set winning team in gamestate (replicated)
	GetGameState<ADefaultGameState>()->gameWinningTeam = team;

	EndMatch();

	// Destroy all player pawns so that they respawn as spectators
	for (int32 i = 0; i < players.Num(); i++)
	{
		if(IsValid(players[i]))
		{
			players[i]->Destroy(true);
		}
	}

	//TPRINT("Boss was killed. (ADefaultGameMode)    the team = " + team);
}

void AKingOfTheHillGameMode::AddScore(int team, float duration)
{
	// team to array index [1-5] -> [0-4]
	team -= 1;
	AKOTHGameState* gameState = GetGameState<AKOTHGameState>();
	if(team < 0 || team >= gameState->kothTeams.Num())
		return;
	gameState->kothTeams[team].score += duration;
	gameState->kothTeams[team].active = 2;
	if(m_currentTeamWithHill != team)
	{
		gameState->BroadcastOnHillCaptured(team);
		m_currentTeamWithHill = team;
	}
}