// Copyright Epic Games, Inc. All Rights Reserved.
// UE5 Modular Game Framework — BPC_StateManager (130)
// Central State Authority. Single source of truth for "what can the player do right now?"
// Manages exclusive action states, upper-body overlay states, action gating,
// vital signs (heart rate), and the force-stack pattern for nested overrides.

#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "GameplayTagContainer.h"
#include "BPC_StateManager.generated.h"

// Forward declarations
class UDA_StateGatingTable;
class UBPC_HealthSystem;
class UBPC_StressSystem;
class UBPC_StaminaSystem;
class UBPC_MovementStateSystem;

// ============================================================================
// Delegates
// ============================================================================

DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnActionStateChanged, FGameplayTag, NewState, FGameplayTag, OldState);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnOverlayStateChanged, FGameplayTag, NewOverlay, FGameplayTag, OldOverlay);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnVitalSignChanged, FGameplayTag, VitalTag, float, NewValue);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnForceStackPushed, FGameplayTag, ForceState);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnForceStackPopped, FGameplayTag, RestoredState);

/**
 * Result codes for state change requests.
 * Mirrors the Blueprint E_ActionRequestResult enum.
 */
UENUM(BlueprintType)
enum class EActionRequestResult : uint8
{
	Granted          UMETA(DisplayName = "Granted"),
	Denied           UMETA(DisplayName = "Denied — Gated"),
	BlockedByForce   UMETA(DisplayName = "Blocked — Force Stack Override"),
	AlreadyActive    UMETA(DisplayName = "Already Active"),
	InvalidState     UMETA(DisplayName = "Invalid State Tag"),
	RequesterNotFound UMETA(DisplayName = "Requester Not Found"),
	CooldownActive   UMETA(DisplayName = "Cooldown Active"),
	VitalThreshold   UMETA(DisplayName = "Vital Threshold Not Met"),
};

/**
 * Heart rate tier for vital sign tracking.
 */
UENUM(BlueprintType)
enum class EHeartRateTier : uint8
{
	Resting    UMETA(DisplayName = "Resting (60-80 BPM)"),
	Elevated   UMETA(DisplayName = "Elevated (80-100 BPM)"),
	Stressed   UMETA(DisplayName = "Stressed (100-130 BPM)"),
	Panic      UMETA(DisplayName = "Panic (130-160 BPM)"),
	Critical   UMETA(DisplayName = "Critical (160+ BPM)"),
};

/**
 * BPC_StateManager — Central State Authority.
 *
 * Every system queries IsActionPermitted(Tag) instead of checking other systems
 * directly. Gating rules are defined in DA_StateGatingTable (37 rules).
 * In C++, the Chooser Table iteration is native-speed — no BP interpretive overhead.
 */
UCLASS(Blueprintable, ClassGroup = (Framework), meta = (BlueprintSpawnableComponent))
class PG_FRAMEWORK_API UBPC_StateManager : public UActorComponent
{
	GENERATED_BODY()

public:
	UBPC_StateManager();

	// ========================================================================
	// Configuration
	// ========================================================================

	/** The gating rules Data Asset. Contains all 37 action rules. */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Framework|Config")
	TObjectPtr<UDA_StateGatingTable> GatingTable;

	/** Default action state on BeginPlay. */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Framework|Config")
	FGameplayTag DefaultActionState;

	/** Default overlay state on BeginPlay. */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Framework|Config")
	FGameplayTag DefaultOverlayState;

	// ========================================================================
	// Core Query — Hot Path
	// ========================================================================

	/**
	 * Central query: "Can the player perform this action right now?"
	 * Called by EVERY gameplay system per-frame. C++ makes this fast.
	 */
	UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|State")
	bool IsActionPermitted(FGameplayTag ActionTag) const;

	/**
	 * Request a state change. Returns the result code.
	 * Server-authoritative.
	 */
	UFUNCTION(BlueprintCallable, Category = "Framework|State")
	EActionRequestResult RequestStateChange(FGameplayTag NewState, AActor* Requester);

	// ========================================================================
	// Current State (Read-Only)
	// ========================================================================

	/** Currently active exclusive action state (only one at a time). */
	UPROPERTY(BlueprintReadOnly, Category = "Framework|State")
	FGameplayTag CurrentActionState;

	/** Currently active upper-body overlay state. */
	UPROPERTY(BlueprintReadOnly, Category = "Framework|State")
	FGameplayTag CurrentOverlayState;

	// ========================================================================
	// Force Stack Pattern (Death, Cutscenes, Void Space)
	// ========================================================================

	/**
	 * Pushes a forced state onto the stack. Overrides all gating.
	 * Example: death overrides everything.
	 */
	UFUNCTION(BlueprintCallable, Category = "Framework|State")
	void ForceStateChange(FGameplayTag ForceState, FString Reason);

	/**
	 * Pops the top forced state and restores the previous state.
	 * Example: respawn restores the pre-death state.
	 */
	UFUNCTION(BlueprintCallable, Category = "Framework|State")
	void RestorePreviousState();

	/** Returns the number of states currently on the force stack. */
	UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|State")
	int32 GetForceStackDepth() const { return ForceStack.Num(); }

	// ========================================================================
	// Vital Signs — Heart Rate
	// ========================================================================

	/** Current heart rate in BPM (smoothed). */
	UPROPERTY(BlueprintReadOnly, Category = "Framework|Vitals")
	float HeartRateBPM = 70.0f;

	/** Current heart rate tier. */
	UPROPERTY(BlueprintReadOnly, Category = "Framework|Vitals")
	EHeartRateTier HeartRateTier = EHeartRateTier::Resting;

	/** Target heart rate (set by stress, stamina, combat). Interpolated toward each tick. */
	UPROPERTY(BlueprintReadOnly, Category = "Framework|Vitals")
	float TargetHeartRate = 70.0f;

	/** Smoothing speed for heart rate interpolation. */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Framework|Vitals")
	float HeartRateSmoothSpeed = 2.0f;

	// ========================================================================
	// Event Dispatchers
	// ========================================================================

	UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
	FOnActionStateChanged OnActionStateChanged;

	UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
	FOnOverlayStateChanged OnOverlayStateChanged;

	UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
	FOnVitalSignChanged OnVitalSignChanged;

	UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
	FOnForceStackPushed OnForceStackPushed;

	UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
	FOnForceStackPopped OnForceStackPopped;

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

	virtual void BeginPlay() override;
	virtual void TickComponent(float DeltaTime, ELevelTick TickType,
		FActorComponentTickFunction* ThisTickFunction) override;

protected:
	// ========================================================================
	// Internal State
	// ========================================================================

	/** Force stack — array of (State, Reason) pairs. Most recent is active. */
	struct FForceStackEntry
	{
		FGameplayTag State;
		FString Reason;
	};

	TArray<FForceStackEntry> ForceStack;

	/** Previous action state before force override (for restore). */
	FGameplayTag PreForceActionState;

	/** Previous overlay state before force override (for restore). */
	FGameplayTag PreForceOverlayState;

	// ========================================================================
	// Gating Logic
	// ========================================================================

	/** Check gating rules for a tag against current state. */
	bool EvaluateGatingRules(FGameplayTag ActionTag) const;

	/** Check if any force stack entry blocks this action. */
	bool IsBlockedByForceStack(FGameplayTag ActionTag) const;

	// ========================================================================
	// Vital Sign Calculation
	// ========================================================================

	/** Recalculates target heart rate based on stress tier + stamina exhaustion + combat. */
	void RecalculateTargetHeartRate();

	/** Determines heart rate tier from current BPM. */
	static EHeartRateTier GetHeartRateTier(float BPM);

	// ========================================================================
	// Binding References (cached in BeginPlay)
	// ========================================================================

	UPROPERTY()
	TObjectPtr<UBPC_HealthSystem> CachedHealthSystem;

	UPROPERTY()
	TObjectPtr<UBPC_StressSystem> CachedStressSystem;

	UPROPERTY()
	TObjectPtr<UBPC_StaminaSystem> CachedStaminaSystem;

	UPROPERTY()
	TObjectPtr<UBPC_MovementStateSystem> CachedMovementSystem;
};
