// Project Lab - NHTV Igad

#include "UnrealProject.h"
#include "MapData.h"
#include "MapSelectionScreen.h"
#include "AssetRegistryModule.h"
#include "DefaultGameInstance.h"
#include "MapSlot.h"
#include "SessionManager.h"
#include "MenuController.h"
#include "ScreenOverlay.h"
#include "MenuGameMode.h"

static UClass* mapSlotWidgetClass;

UMapSelectionScreen::UMapSelectionScreen(const FObjectInitializer& init)
	: Super(init)
{
	mapSlotWidgetClass = ConstructorHelpers::FClassFinder<UMapSlot>(TEXT("/Game/Assets/GUI/Components/WEEGEE_MapListItem")).Class;
}

void UMapSelectionScreen::NativeConstruct()
{
	Super::NativeConstruct();
	if(container)
	{
		// Get all the available maps and create selection buttons for them
		UWorld* world = GetWorld();
		check(world);
		auto& maps = Cast<UDefaultGameInstance>(world->GetGameInstance())->maps;
		for(int32 i = 0; i < maps.Num(); i++)
		{
			UMapSlot* mapSlot = CreateWidget<UMapSlot>(GetWorld(), mapSlotWidgetClass);
			check(mapSlot);
			mapSlot->mapData = maps[i];
			mapSlot->mapScreen = this;
			mapSlot->OnMapSet();
			m_mapSlots.Add(mapSlot);
			container->AddChild(mapSlot);
		}

		onItemSelected.RemoveAll(this);
		onItemSelected.AddDynamic(this, &UMapSelectionScreen::OnSelectionChanged);
		RescanItems();
		SelectMap(0);
	}
}

void UMapSelectionScreen::OnSelectionChanged(UMenuItemBase* item)
{
	UMapSlot* mapSlot = Cast<UMapSlot>(item);
	if(mapSlot)
	{
		//SelectMap(mapSlot->index);
	}
}
void UMapSelectionScreen::SelectMap(int32 index)
{
	UWorld* world = GetWorld();
	check(world);
	UDefaultGameInstance* inst = Cast<UDefaultGameInstance>(world->GetGameInstance());

	TArray<UMapData*>& maps = inst->maps;
	if(index < 0 || index > maps.Num())
	{
		GWERROR(L"Selected map out of range");
		return;
	}

	mapData = maps[index];
	check(mapData);

	// Set the asset path to the selected map in the session manager
	AMenuGameMode* gameMode = Cast<AMenuGameMode>(world->GetAuthGameMode());
	if(gameMode)
	{
		gameMode->SetMap(mapData->pathToAsset);
		GWPRINT(L"Selected map: " + maps[index]->friendlyName);
	}
	else
	{
		GWARNING(L"Can't select map, no game mode!");
	}
}

void UMapSelectionScreen::CreateGame()
{
	SelectMap(GetSelectedItem());

	if(!mapData)
	{
		GERROR("No map set");
		return;
	}

	UWorld* world = GetWorld();
	check(world);
	UDefaultGameInstance* inst = Cast<UDefaultGameInstance>(world->GetGameInstance());

	AMenuGameMode* gameMode = Cast<AMenuGameMode>(world->GetAuthGameMode());
	if(!gameMode)
	{
		GERROR("Can't start game, no menu game mode set");
		return;
	}

	APlayerControllerBase* pc = Cast<APlayerControllerBase>(GetOwningPlayer());
	if(m_sessionCreateOverlay)
		return; // Already creating session
	m_sessionCreateOverlay = pc->overlay->ShowOverlay("Creating session");

	// Set the map setting in the game mode
	gameMode->AssignMapData(mapData);

	// Make sure there is no connection already
	inst->sessionManager->CloseNetConnections();

	// Set host settings
	FOnlineSessionSettings& sessionSettings = inst->sessionManager->sessionSettings;
	sessionSettings.NumPublicConnections = mapData->maxTeamCount * 2; // Team count setting translated to max connected players (x2)
	sessionSettings.Set(SETTING_MAPNAME, mapData->pathToAsset, EOnlineDataAdvertisementType::ViaOnlineServiceAndPing);

	// Create a new session
	inst->sessionManager->onCreateSessionComplete.AddUObject(this, &UMapSelectionScreen::m_OnCreateSessionCompleted);
	inst->sessionManager->CreateSession();
}

void UMapSelectionScreen::m_OnCreateSessionCompleted(bool success)
{
	if(m_sessionCreateOverlay)
	{
		m_sessionCreateOverlay->Close();
		m_sessionCreateOverlay = nullptr;
	}

	UDefaultGameInstance* inst = Cast<UDefaultGameInstance>(GetWorld()->GetGameInstance());
	inst->sessionManager->onCreateSessionComplete.RemoveAll(this);

	AMenuController* mc = Cast<AMenuController>(GetOwningPlayer());
	if(success)
	{
		// Goto the lobby
		mc->OnEnterLobby();

		// Start the session, @note not sure if this is needed
		//inst->sessionManager->StartSession();
	}
	else
	{
		TArray<FString> options;
		options.Add("OK");
		mc->overlay->ShowMessageBox("Error", "Failed to create game session", options);
	}
}

UMapData::UMapData()
{
	maxTeamCount = 3;
	friendlyName = "Map Name";
	description = "<Designers: Add description>";
}