// © 2025 Naked People Team. All Rights Reserved.


#include "SessionManagerSubsystem.h"

#include "Kismet/GameplayStatics.h"
#include "NakedDesire/Global/Constants.h"
#include "NakedDesire/Global/NakedDesireGameplayTags.h"
#include "NakedDesire/Locations/LocationData.h"
#include "NakedDesire/Locations/LocationSubsystem.h"
#include "NakedDesire/Player/NakedDesireCharacter.h"
#include "NakedDesire/Stats/StatsManager.h"

void USessionManagerSubsystem::OnWorldBeginPlay(UWorld& InWorld)
{
	Super::OnWorldBeginPlay(InWorld);

	// The apartment threshold is now a location event (Location.Apartment), not a per-trigger flag.
	if (ULocationSubsystem* Locations = InWorld.GetSubsystem<ULocationSubsystem>())
	{
		Locations->OnLocationEntered.AddDynamic(this, &USessionManagerSubsystem::HandleLocationEntered);
		Locations->OnLocationExited.AddDynamic(this, &USessionManagerSubsystem::HandleLocationExited);
	}

	// The player pawn and its UStatsManager may not have finished BeginPlay when
	// the world begins play, so defer binding by one tick.
	InWorld.GetTimerManager().SetTimerForNextTick(this, &USessionManagerSubsystem::BindToPlayerStats);
}

void USessionManagerSubsystem::BindToPlayerStats()
{
	ANakedDesireCharacter* Player = Cast<ANakedDesireCharacter>(UGameplayStatics::GetPlayerCharacter(this, SLOT_PLAYER));
	if (!Player || !Player->StatsManager)
	{
		UE_LOG(LogTemp, Warning, TEXT("USessionManagerSubsystem: no player StatsManager to bind to; loss detection disabled."));
		return;
	}

	Player->StatsManager->EmbarrassmentUpdate.AddDynamic(this, &USessionManagerSubsystem::HandleEmbarrassmentUpdate);
	Player->StatsManager->EnergyUpdate.AddDynamic(this, &USessionManagerSubsystem::HandleEnergyUpdate);
}

void USessionManagerSubsystem::HandleLocationEntered(ULocationData* Location)
{
	// Returning to the apartment is the safe end of a session (§4.3).
	if (Location && Location->Tag.MatchesTag(TAG_Location_Apartment) && bSessionActive)
	{
		EndSession(ESessionLossCause::SafeReturn);
	}
}

void USessionManagerSubsystem::HandleLocationExited(ULocationData* Location)
{
	// Leaving the apartment is the only way to start a session (§4.1).
	if (Location && Location->Tag.MatchesTag(TAG_Location_Apartment) && !bSessionActive)
	{
		StartSession();
	}
}

void USessionManagerSubsystem::StartSession()
{
	bSessionActive = true;
	OnSessionStart.Broadcast();
}

void USessionManagerSubsystem::EndSession(const ESessionLossCause Cause)
{
	if (!bSessionActive)
		return;

	bSessionActive = false;
	OnSessionEnd.Broadcast(Cause);
}

void USessionManagerSubsystem::HandleEmbarrassmentUpdate(const float CurrentValue, const float MaxValue)
{
	if (bSessionActive && MaxValue > 0.0f && CurrentValue >= MaxValue)
	{
		EndSession(ESessionLossCause::EmbarrassmentMax);
	}
}

void USessionManagerSubsystem::HandleEnergyUpdate(const float CurrentValue, const float MaxValue)
{
	if (bSessionActive && CurrentValue <= 0.0f)
	{
		EndSession(ESessionLossCause::EnergyZero);
	}
}