// Copyright Epic Games, Inc. All Rights Reserved.
// UE5 Modular Game Framework — GS_CoreGameState Implementation

#include "Core/GS_CoreGameState.h"
#include "Core/GI_GameFramework.h"
#include "Net/UnrealNetwork.h"

DEFINE_LOG_CATEGORY_STATIC(LogFrameworkGameState, Log, All);

AGS_CoreGameState::AGS_CoreGameState()
{
	PrimaryActorTick.bCanEverTick = true;
	PrimaryActorTick.TickInterval = 0.1f; // 10Hz tick for time accumulation.
}

// ============================================================================
// Replication
// ============================================================================

void AGS_CoreGameState::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);

	DOREPLIFETIME(AGS_CoreGameState, ElapsedPlayTime);
	DOREPLIFETIME(AGS_CoreGameState, ActiveChapterTag);
	DOREPLIFETIME(AGS_CoreGameState, ActiveNarrativePhase);
	DOREPLIFETIME(AGS_CoreGameState, bEncounterActive);
	DOREPLIFETIME(AGS_CoreGameState, ActiveObjectiveTags);
}

// ============================================================================
// Overrides
// ============================================================================

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

	CachedFramework = Cast<UGI_GameFramework>(GetGameInstance());

	if (CachedFramework)
	{
		UE_LOG(LogFrameworkGameState, Log, TEXT("GS_CoreGameState::BeginPlay — Bound to GI_GameFramework"));
	}
	else
	{
		UE_LOG(LogFrameworkGameState, Warning, TEXT("GS_CoreGameState::BeginPlay — GI_GameFramework not found!"));
	}
}

void AGS_CoreGameState::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	// Only accumulate time when InGame phase is active.
	if (CachedFramework && CachedFramework->CurrentGamePhase == EGamePhase::InGame)
	{
		ElapsedPlayTime += DeltaTime;

		// Throttled broadcast (~1/sec).
		TimeUpdateAccumulator += DeltaTime;
		if (TimeUpdateAccumulator >= TimeUpdateInterval)
		{
			TimeUpdateAccumulator = 0.0f;
			OnElapsedPlayTimeUpdated.Broadcast(ElapsedPlayTime);
		}
	}
}

// ============================================================================
// Setters (Server-Authoritative)
// ============================================================================

void AGS_CoreGameState::SetChapter(FGameplayTag ChapterTag)
{
	if (!ChapterTag.IsValid())
	{
		return;
	}

	if (ActiveChapterTag == ChapterTag)
	{
		return; // No change.
	}

	ActiveChapterTag = ChapterTag;

	UE_LOG(LogFrameworkGameState, Log, TEXT("GS_CoreGameState::SetChapter — '%s'"), *ChapterTag.GetTagName().ToString());

	// Broadcast for local (server/listen-host).
	OnChapterChanged.Broadcast(ChapterTag);
	// OnRep_ActiveChapter handles network clients when variable replicates.
}

void AGS_CoreGameState::SetNarrativePhase(FGameplayTag PhaseTag)
{
	if (!PhaseTag.IsValid())
	{
		return;
	}

	if (ActiveNarrativePhase == PhaseTag)
	{
		return;
	}

	ActiveNarrativePhase = PhaseTag;

	UE_LOG(LogFrameworkGameState, Verbose, TEXT("GS_CoreGameState::SetNarrativePhase — '%s'"), *PhaseTag.GetTagName().ToString());

	OnNarrativePhaseChanged.Broadcast(PhaseTag);
}

void AGS_CoreGameState::SetEncounterActive(bool bActive)
{
	if (bEncounterActive == bActive)
	{
		return;
	}

	bEncounterActive = bActive;

	UE_LOG(LogFrameworkGameState, Log, TEXT("GS_CoreGameState::SetEncounterActive — %s"), bActive ? TEXT("Active") : TEXT("Inactive"));

	OnEncounterActiveStateChanged.Broadcast(bActive);
}

void AGS_CoreGameState::AddObjective(FGameplayTag ObjectiveTag)
{
	if (!ObjectiveTag.IsValid())
	{
		return;
	}

	if (ActiveObjectiveTags.Contains(ObjectiveTag))
	{
		return; // Duplicate prevention.
	}

	ActiveObjectiveTags.Add(ObjectiveTag);

	UE_LOG(LogFrameworkGameState, Log, TEXT("GS_CoreGameState::AddObjective — '%s'"), *ObjectiveTag.GetTagName().ToString());

	OnObjectiveTagsChanged.Broadcast();
}

void AGS_CoreGameState::RemoveObjective(FGameplayTag ObjectiveTag)
{
	if (ActiveObjectiveTags.Remove(ObjectiveTag) > 0)
	{
		UE_LOG(LogFrameworkGameState, Log, TEXT("GS_CoreGameState::RemoveObjective — '%s'"), *ObjectiveTag.GetTagName().ToString());
		OnObjectiveTagsChanged.Broadcast();
	}
}

void AGS_CoreGameState::ClearAllObjectives()
{
	if (ActiveObjectiveTags.Num() > 0)
	{
		ActiveObjectiveTags.Empty();
		UE_LOG(LogFrameworkGameState, Log, TEXT("GS_CoreGameState::ClearAllObjectives"));
		OnObjectiveTagsChanged.Broadcast();
	}
}

// ============================================================================
// OnRep Handlers
// ============================================================================

void AGS_CoreGameState::OnRep_ElapsedPlayTime()
{
	OnElapsedPlayTimeUpdated.Broadcast(ElapsedPlayTime);
}

void AGS_CoreGameState::OnRep_ActiveChapter()
{
	OnChapterChanged.Broadcast(ActiveChapterTag);
}

void AGS_CoreGameState::OnRep_NarrativePhase()
{
	OnNarrativePhaseChanged.Broadcast(ActiveNarrativePhase);
}

void AGS_CoreGameState::OnRep_EncounterActive()
{
	OnEncounterActiveStateChanged.Broadcast(bEncounterActive);
}

void AGS_CoreGameState::OnRep_ObjectiveTags()
{
	OnObjectiveTagsChanged.Broadcast();
}
