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

#pragma once

#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "CommissionTypes.h"
#include "Commission.generated.h"

class UCommissionObjective;
class ANakedDesireCharacter;
class UCommission;

DECLARE_MULTICAST_DELEGATE_OneParam(FOnCommissionChangedSignature, UCommission*);

/**
 * A commission (GDD §13). Authored inline in a UCommissionBoardConfig and duplicated to a runtime
 * instance by UMissionSubsystem; the duplicate owns the state machine and its live objectives.
 * Completes when every objective reports satisfied; the subsystem pays the reward and persists state.
 */
UCLASS(EditInlineNew, BlueprintType)
class NAKEDDESIRE_API UCommission : public UObject
{
	GENERATED_BODY()

public:
	// --- Authoring ---
	// Stable id used for save/restore (must be unique within the board config).
	UPROPERTY(EditDefaultsOnly)
	FName CommissionId;

	UPROPERTY(EditDefaultsOnly)
	FText Title;

	// Lore-only forum poster (§13.3) — no gameplay effect.
	UPROPERTY(EditDefaultsOnly)
	FText PosterUsername;

	UPROPERTY(EditDefaultsOnly)
	ECommissionTier Tier = ECommissionTier::Daily;

	UPROPERTY(EditDefaultsOnly)
	FCommissionReward Reward;

	UPROPERTY(EditDefaultsOnly, Instanced)
	TArray<UCommissionObjective*> Objectives;

	// When true, objectives activate one at a time in array order (strip at A -> walk to B -> ... ).
	// When false (default), all objectives are active at once and may be satisfied in any order.
	UPROPERTY(EditDefaultsOnly)
	bool bSequentialObjectives = false;

	// --- Runtime ---
	FOnCommissionChangedSignature OnStateChanged; // any transition
	FOnCommissionChangedSignature OnCompleted;    // -> Completed

	ECommissionState GetState() const { return State; }

	UFUNCTION(BlueprintPure) ECommissionTier GetTier() const { return Tier; }
	UFUNCTION(BlueprintPure) FText GetTitle() const { return Title; }
	UFUNCTION(BlueprintPure) FText GetPosterUsername() const { return PosterUsername; }
	UFUNCTION(BlueprintPure) FCommissionReward GetReward() const { return Reward; }
	UFUNCTION(BlueprintPure) TArray<UCommissionObjective*> GetObjectives() const { return Objectives; }

	void Accept(ANakedDesireCharacter* InPlayer);  // Offered -> Accepted; arms objectives
	void Abandon();                                // Accepted -> Offered; no penalty (§13.2)
	void Expire();                                 // Accepted -> Expired (deadline)

	// Re-apply a persisted state on load (re-arms objectives when restoring Accepted).
	void RestoreState(ECommissionState SavedState, ANakedDesireCharacter* InPlayer);

private:
	void Complete();
	bool AreAllObjectivesSatisfied() const;
	void ArmObjectives();
	void DisarmObjectives();
	void AdvanceSequential(); // activate the first unsatisfied objective, or complete if none remain
	void SetState(ECommissionState NewState);

	void HandleObjectiveStateChanged(UCommissionObjective* Objective);

	ECommissionState State = ECommissionState::Offered;
	int32 ActiveObjectiveIndex = INDEX_NONE; // sequential mode: the objective currently armed

	UPROPERTY()
	ANakedDesireCharacter* Player = nullptr;
};