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


#include "CommissionObjective.h"

#include "TimerManager.h"
#include "CommissionConstraint.h"
#include "NakedDesire/Player/NakedDesireCharacter.h"

void UCommissionObjective::Activate(ANakedDesireCharacter* InPlayer)
{
	Player = InPlayer;
	bSatisfied = false;

	OnActivate();

	for (UCommissionConstraint* Constraint : Constraints)
	{
		if (!Constraint)
			continue;
		Constraint->OnConstraintChanged.AddUObject(this, &UCommissionObjective::HandleConstraintChanged);
		Constraint->Activate(Player);
	}

	NotifyConditionChanged(); // evaluate the starting state (e.g. already naked on accept)
}

void UCommissionObjective::Deactivate()
{
	ClearHoldTimer();

	for (UCommissionConstraint* Constraint : Constraints)
	{
		if (!Constraint)
			continue;
		Constraint->OnConstraintChanged.RemoveAll(this);
		Constraint->Deactivate();
	}

	OnDeactivate();
	Player = nullptr;
}

bool UCommissionObjective::AreConstraintsMet() const
{
	for (const UCommissionConstraint* Constraint : Constraints)
	{
		if (Constraint && !Constraint->IsMet())
			return false;
	}
	return true;
}

void UCommissionObjective::HandleConstraintChanged()
{
	NotifyConditionChanged();
}

void UCommissionObjective::NotifyConditionChanged()
{
	if (bSatisfied || !Player)
		return;

	if (IsConditionMet() && AreConstraintsMet())
	{
		if (RequiredHoldSeconds <= 0.0f)
		{
			MarkSatisfied();
			return;
		}

		if (!HoldTimerHandle.IsValid())
		{
			HoldStartTime = Player->GetWorld()->GetTimeSeconds();
			Player->GetWorldTimerManager().SetTimer(HoldTimerHandle, this, &UCommissionObjective::OnHoldElapsed, RequiredHoldSeconds, false);
		}
	}
	else
	{
		ClearHoldTimer();
	}
}

void UCommissionObjective::OnHoldElapsed()
{
	MarkSatisfied();
}

void UCommissionObjective::MarkSatisfied()
{
	if (bSatisfied)
		return;

	bSatisfied = true;
	ClearHoldTimer();
	OnStateChanged.Broadcast(this);
}

void UCommissionObjective::ClearHoldTimer()
{
	if (HoldTimerHandle.IsValid() && Player)
		Player->GetWorldTimerManager().ClearTimer(HoldTimerHandle);

	HoldTimerHandle.Invalidate();
	HoldStartTime = 0.0f;
}

FText UCommissionObjective::GetDescription() const
{
	return FText::GetEmpty();
}

FText UCommissionObjective::GetConstraintsDescription() const
{
	TArray<FString> Parts;
	for (const UCommissionConstraint* Constraint : Constraints)
	{
		if (!Constraint)
			continue;

		const FString Text = Constraint->GetDescription().ToString();
		if (!Text.IsEmpty())
			Parts.Add(Text);
	}
	return FText::FromString(FString::Join(Parts, TEXT(", ")));
}

float UCommissionObjective::GetProgress() const
{
	if (bSatisfied)
		return 1.0f;

	if (HoldTimerHandle.IsValid() && Player && RequiredHoldSeconds > 0.0f)
	{
		const float Elapsed = Player->GetWorld()->GetTimeSeconds() - HoldStartTime;
		return FMath::Clamp(Elapsed / RequiredHoldSeconds, 0.0f, 1.0f);
	}

	return 0.0f;
}