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


#include "ForumCommissionWidget.h"

#include "Components/Button.h"
#include "CommonTextBlock.h"
#include "NakedDesire/Commissions/Commission.h"
#include "NakedDesire/Commissions/CommissionObjective.h"
#include "NakedDesire/Commissions/CommissionTypes.h"

#define LOCTEXT_NAMESPACE "ForumCommission"

void UForumCommissionWidget::NativeOnInitialized()
{
	Super::NativeOnInitialized();

	if (AcceptButton)
		AcceptButton->OnClicked.AddUniqueDynamic(this, &UForumCommissionWidget::HandleAcceptClicked);

	if (AbandonButton)
		AbandonButton->OnClicked.AddUniqueDynamic(this, &UForumCommissionWidget::HandleAbandonClicked);
}

void UForumCommissionWidget::SetCommission(UCommission* InCommission)
{
	Commission = InCommission;
	CachedObjectivesString.Reset(); // force a fresh push for the (possibly reused) row
	TimeSinceProgressRefresh = 0.0f;
	if (!Commission)
		return;

	if (TitleText)
		TitleText->SetText(Commission->GetTitle());

	if (PosterText)
		PosterText->SetText(FText::Format(LOCTEXT("PosterFmt", "by {0}"), Commission->GetPosterUsername()));

	if (RewardText)
		RewardText->SetText(FormatReward(Commission->GetReward()));

	UpdateObjectivesText();

	// Accept only offers; abandon only commitments. Completed / expired rows show neither control.
	const ECommissionState State = Commission->GetState();
	if (AcceptButton)
		AcceptButton->SetVisibility(State == ECommissionState::Offered ? ESlateVisibility::Visible : ESlateVisibility::Collapsed);
	if (AbandonButton)
		AbandonButton->SetVisibility(State == ECommissionState::Accepted ? ESlateVisibility::Visible : ESlateVisibility::Collapsed);
}

void UForumCommissionWidget::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
{
	Super::NativeTick(MyGeometry, InDeltaTime);

	// Only accepted rows have live progress; offered / completed / expired rows are static.
	if (!Commission || Commission->GetState() != ECommissionState::Accepted)
		return;

	TimeSinceProgressRefresh += InDeltaTime;
	if (TimeSinceProgressRefresh < ProgressRefreshInterval)
		return;

	TimeSinceProgressRefresh = 0.0f;
	UpdateObjectivesText();
}

void UForumCommissionWidget::HandleAcceptClicked()
{
	if (Commission)
		OnAcceptClicked.ExecuteIfBound(Commission);
}

void UForumCommissionWidget::HandleAbandonClicked()
{
	if (Commission)
		OnAbandonClicked.ExecuteIfBound(Commission);
}

void UForumCommissionWidget::UpdateObjectivesText()
{
	if (!DescriptionText)
		return;

	FString NewText = BuildObjectivesString();
	if (NewText == CachedObjectivesString)
		return; // nothing changed since the last refresh — skip the SetText churn

	CachedObjectivesString = MoveTemp(NewText);
	DescriptionText->SetText(FText::FromString(CachedObjectivesString));
}

FString UForumCommissionWidget::BuildObjectivesString() const
{
	FString Result;
	if (!Commission)
		return Result;

	for (const UCommissionObjective* Objective : Commission->GetObjectives())
	{
		if (!Objective)
			continue;

		if (!Result.IsEmpty())
			Result += LINE_TERMINATOR;

		FString Line = FString::Printf(TEXT("• %s"), *Objective->GetDescription().ToString());

		// Append any "while Y" constraint text so the row reads "Be fully naked while at Beach (50%)".
		const FString Constraints = Objective->GetConstraintsDescription().ToString();
		if (!Constraints.IsEmpty())
			Line += FString::Printf(TEXT(" %s"), *Constraints);

		const int32 Pct = FMath::RoundToInt(Objective->GetProgress() * 100.0f);
		Line += FString::Printf(TEXT(" (%d%%)"), Pct);

		Result += Line;
	}
	return Result;
}

FText UForumCommissionWidget::FormatReward(const FCommissionReward& Reward)
{
	TArray<FString> Parts;
	if (Reward.Money != 0)
		Parts.Add(FString::Printf(TEXT("¥%d"), Reward.Money)); // ¥ = yen sign
	if (!FMath::IsNearlyZero(Reward.XP))
		Parts.Add(FString::Printf(TEXT("%.0f XP"), Reward.XP));
	if (Reward.Followers != 0)
		Parts.Add(FString::Printf(TEXT("+%d followers"), Reward.Followers));

	return FText::FromString(FString::Join(Parts, TEXT("   ")));
}

#undef LOCTEXT_NAMESPACE