// Copyright Epic Games, Inc. All Rights Reserved.


#include "AgrarianGamePlayerController.h"
#include "AgrarianGameCharacter.h"
#include "AgrarianInventoryComponent.h"
#include "AgrarianPersistenceSubsystem.h"
#include "AgrarianShelterActor.h"
#include "AgrarianSurvivalComponent.h"
#include "EnhancedInputSubsystems.h"
#include "Engine/LocalPlayer.h"
#include "InputMappingContext.h"
#include "Blueprint/UserWidget.h"
#include "AgrarianGame.h"
#include "Widgets/Input/SVirtualJoystick.h"

void AAgrarianGamePlayerController::BeginPlay()
{
	Super::BeginPlay();

	// only spawn touch controls on local player controllers
	if (ShouldUseTouchControls() && IsLocalPlayerController())
	{
		// spawn the mobile controls widget
		MobileControlsWidget = CreateWidget<UUserWidget>(this, MobileControlsWidgetClass);

		if (MobileControlsWidget)
		{
			// add the controls to the player screen
			MobileControlsWidget->AddToPlayerScreen(0);

		} else {

			UE_LOG(LogAgrarianGame, Error, TEXT("Could not spawn mobile controls widget."));

		}

	}
}

void AAgrarianGamePlayerController::SetupInputComponent()
{
	Super::SetupInputComponent();

	// only add IMCs for local player controllers
	if (IsLocalPlayerController())
	{
		// Add Input Mapping Contexts
		if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer()))
		{
			for (UInputMappingContext* CurrentContext : DefaultMappingContexts)
			{
				Subsystem->AddMappingContext(CurrentContext, 0);
			}

			// only add these IMCs if we're not using mobile touch input
			if (!ShouldUseTouchControls())
			{
				for (UInputMappingContext* CurrentContext : MobileExcludedMappingContexts)
				{
					Subsystem->AddMappingContext(CurrentContext, 0);
				}
			}
		}
	}
}

bool AAgrarianGamePlayerController::ShouldUseTouchControls() const
{
	// are we on a mobile platform? Should we force touch?
	return SVirtualJoystick::ShouldDisplayTouchInterface() || bForceTouchControls;
}

void AAgrarianGamePlayerController::AgrarianGrantItem(FName ItemId, int32 Quantity)
{
	if (ItemId == NAME_None || Quantity <= 0)
	{
		ClientMessage(TEXT("Usage: AgrarianGrantItem <ItemId> <Quantity>"));
		return;
	}

	ServerAgrarianGrantItem(ItemId, Quantity);
}

void AAgrarianGamePlayerController::AgrarianSaveWorld()
{
	ServerAgrarianSaveWorld();
}

void AAgrarianGamePlayerController::AgrarianLoadWorld()
{
	ServerAgrarianLoadWorld();
}

void AAgrarianGamePlayerController::AgrarianSurvival()
{
	const AAgrarianGameCharacter* AgrarianCharacter = GetPawn<AAgrarianGameCharacter>();
	const UAgrarianSurvivalComponent* SurvivalComponent = AgrarianCharacter ? AgrarianCharacter->GetSurvivalComponent() : nullptr;
	if (!SurvivalComponent)
	{
		ClientMessage(TEXT("No Agrarian survival component found."));
		return;
	}

	const FAgrarianSurvivalSnapshot& Survival = SurvivalComponent->Survival;
	ClientMessage(FString::Printf(
		TEXT("Health %.1f | Stamina %.1f | Exhaustion %.1f | Hunger %.1f | Thirst %.1f | Temp %.1fC | Injury %.1f | Sickness %.1f"),
		Survival.Health,
		Survival.Stamina,
		Survival.Exhaustion,
		Survival.Hunger,
		Survival.Thirst,
		Survival.BodyTemperature,
		Survival.InjurySeverity,
		Survival.SicknessSeverity));
}

void AAgrarianGamePlayerController::AgrarianHeal()
{
	ServerAgrarianHeal();
}

void AAgrarianGamePlayerController::ServerAgrarianGrantItem_Implementation(FName ItemId, int32 Quantity)
{
	AAgrarianGameCharacter* AgrarianCharacter = GetPawn<AAgrarianGameCharacter>();
	UAgrarianInventoryComponent* InventoryComponent = AgrarianCharacter ? AgrarianCharacter->GetInventoryComponent() : nullptr;
	if (!InventoryComponent)
	{
		ClientMessage(TEXT("No Agrarian inventory component found."));
		return;
	}

	FAgrarianItemStack Stack;
	Stack.ItemId = ItemId;
	Stack.DisplayName = FText::FromName(ItemId);
	Stack.Quantity = Quantity;

	if (InventoryComponent->AddItem(Stack))
	{
		ClientMessage(FString::Printf(TEXT("Granted %d x %s."), Quantity, *ItemId.ToString()));
	}
	else
	{
		ClientMessage(FString::Printf(TEXT("Failed to grant %d x %s."), Quantity, *ItemId.ToString()));
	}
}

void AAgrarianGamePlayerController::ServerAgrarianSaveWorld_Implementation()
{
	UAgrarianPersistenceSubsystem* Persistence = GetGameInstance() ? GetGameInstance()->GetSubsystem<UAgrarianPersistenceSubsystem>() : nullptr;
	if (!Persistence)
	{
		ClientMessage(TEXT("No Agrarian persistence subsystem found."));
		return;
	}

	const bool bSaved = Persistence->SaveCurrentWorld();
	ClientMessage(bSaved ? TEXT("Agrarian world saved.") : TEXT("Agrarian world save failed."));
}

void AAgrarianGamePlayerController::ServerAgrarianLoadWorld_Implementation()
{
	UAgrarianPersistenceSubsystem* Persistence = GetGameInstance() ? GetGameInstance()->GetSubsystem<UAgrarianPersistenceSubsystem>() : nullptr;
	if (!Persistence)
	{
		ClientMessage(TEXT("No Agrarian persistence subsystem found."));
		return;
	}

	Persistence->RegisterWorldActorClass(TEXT("primitive_shelter"), AAgrarianShelterActor::StaticClass());
	int32 RestoredPlayerCount = 0;
	int32 RestoredActorCount = 0;
	const bool bLoaded = Persistence->LoadCurrentWorld(RestoredPlayerCount, RestoredActorCount);
	ClientMessage(FString::Printf(
		TEXT("%s Restored players: %d. Restored actors: %d."),
		bLoaded ? TEXT("Agrarian world loaded.") : TEXT("Agrarian world load restored actors/players, but world state restore failed."),
		RestoredPlayerCount,
		RestoredActorCount));
}

void AAgrarianGamePlayerController::ServerAgrarianHeal_Implementation()
{
	AAgrarianGameCharacter* AgrarianCharacter = GetPawn<AAgrarianGameCharacter>();
	UAgrarianSurvivalComponent* SurvivalComponent = AgrarianCharacter ? AgrarianCharacter->GetSurvivalComponent() : nullptr;
	if (!SurvivalComponent)
	{
		ClientMessage(TEXT("No Agrarian survival component found."));
		return;
	}

	SurvivalComponent->RestoreHealth(100.0f);
	SurvivalComponent->AddFood(100.0f);
	SurvivalComponent->AddWater(100.0f);
	SurvivalComponent->ReduceExhaustion(100.0f);
	SurvivalComponent->ReduceSickness(100.0f);
	SurvivalComponent->AddWarmth(37.0f - SurvivalComponent->Survival.BodyTemperature);
	ClientMessage(TEXT("Agrarian survival restored."));
}
