// Copyright Epic Games, Inc. All Rights Reserved.
// UE5 Modular Game Framework — Framework Interfaces (03)
// All 9 Blueprint Interfaces defined in C++ for clean default values and type safety.

#pragma once

#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "GameplayTagContainer.h"
#include "I_InterfaceLibrary.generated.h"

// ============================================================================
// Forward Declarations
// ============================================================================

class UDA_ItemData;
class UDA_InteractionData;

// ============================================================================
// I_Interactable — World objects the player can interact with
// ============================================================================

UINTERFACE(MinimalAPI, BlueprintType)
class UInteractable : public UInterface
{
	GENERATED_BODY()
};

class PG_FRAMEWORK_API IInteractable
{
	GENERATED_BODY()

public:
	/** Called when a player interacts with this object. Returns true if interaction succeeded. */
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	bool OnInteract(AActor* Interactor);

	/** Called when crosshair/focus enters this object. */
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	void OnFocusBegin(AActor* Interactor);

	/** Called when crosshair/focus leaves this object. */
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	void OnFocusEnd(AActor* Interactor);

	/** Returns the interaction prompt text (e.g. "Open Door", "Pick Up"). */
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	FText GetInteractionPrompt() const;

	/** Returns whether interaction is currently possible. BlockReason explains why if false. */
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	bool CanInteract(AActor* Interactor, FText& OutBlockReason) const;

	/** Returns the GameplayTag identifying the interaction type (e.g. Framework.Interaction.Type.Pickup). */
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	FGameplayTag GetInteractionType() const;
};

// ============================================================================
// I_Inspectable — Objects that can be examined in 3D inspect mode
// ============================================================================

UINTERFACE(MinimalAPI, BlueprintType)
class UInspectable : public UInterface
{
	GENERATED_BODY()
};

class PG_FRAMEWORK_API IInspectable
{
	GENERATED_BODY()

public:
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	void StartInspect(AActor* Inspector);

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	void EndInspect(AActor* Inspector);

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	void RotateInspect(FRotator RotationDelta);

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	bool GetInspectData(FVector& OutAnchorPoint, FRotator& OutDefaultRotation, float& OutZoomDistance) const;

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	bool HasInspectInfo() const;
};

// ============================================================================
// I_Damageable — Anything that takes damage or can be healed
// ============================================================================

UINTERFACE(MinimalAPI, BlueprintType)
class UDamageable : public UInterface
{
	GENERATED_BODY()
};

class PG_FRAMEWORK_API IDamageable
{
	GENERATED_BODY()

public:
	/** Apply damage. Returns actual damage dealt after modifiers. */
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Combat")
	float TakeDamage(float DamageAmount, AActor* DamageCauser, FGameplayTag DamageType, FVector HitLocation, FVector HitDirection);

	/** Heal by amount. Returns actual health restored. */
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Combat")
	float Heal(float HealAmount, AActor* Healer);

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Combat")
	bool IsAlive() const;

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Combat")
	float GetCurrentHealth() const;

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Combat")
	float GetMaxHealth() const;

	/** Called when health reaches zero. */
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Combat")
	void OnDeath(AActor* Killer, FGameplayTag DeathCause);

	/** Returns multiplier for incoming damage (e.g. 1.5 = takes 50% more damage). */
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Combat")
	float GetDamageModifier(FGameplayTag DamageType) const;
};

// ============================================================================
// I_Holdable — Physics objects the player can grab and manipulate
// ============================================================================

UINTERFACE(MinimalAPI, BlueprintType)
class UHoldable : public UInterface
{
	GENERATED_BODY()
};

class PG_FRAMEWORK_API IHoldable
{
	GENERATED_BODY()

public:
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	void OnPickup(AActor* Holder);

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	void OnDrop(AActor* Dropper);

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	FTransform GetHoldTransform() const;

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	bool IsHeld() const;

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	void OnReleasedFromHold();
};

// ============================================================================
// I_Lockable — Objects that can be locked/unlocked with key items
// ============================================================================

UINTERFACE(MinimalAPI, BlueprintType)
class ULockable : public UInterface
{
	GENERATED_BODY()
};

class PG_FRAMEWORK_API ILockable
{
	GENERATED_BODY()

public:
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	bool TryLock(AActor* Locker);

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	bool TryUnlock(AActor* Unlocker, FGameplayTag KeyTag);

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	bool IsLocked() const;

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	FGameplayTag GetRequiredKeyTag() const;

	/** Broadcast when lock state changes (implementor fires via delegate). */
	virtual void OnLockStateChanged(bool bNewLocked) {}
};

// ============================================================================
// I_UsableItem — Items that can be used from inventory/quick-slots
// ============================================================================

UINTERFACE(MinimalAPI, BlueprintType)
class UUsableItem : public UInterface
{
	GENERATED_BODY()
};

class PG_FRAMEWORK_API IUsableItem
{
	GENERATED_BODY()

public:
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Inventory")
	bool UseItem(AActor* User, AActor* Target);

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Inventory")
	bool CanUseItem(AActor* User, AActor* Target) const;

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Inventory")
	float GetUseDuration() const;

	/** Called after UseItem completes (for animations, effects). */
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Inventory")
	void OnItemUsed(AActor* User);
};

// ============================================================================
// I_Persistable — Actors that save/load their state to disk
// ============================================================================

UINTERFACE(MinimalAPI, BlueprintType)
class UPersistable : public UInterface
{
	GENERATED_BODY()
};

class PG_FRAMEWORK_API IPersistable
{
	GENERATED_BODY()

public:
	/** Serialize state to a byte array for saving. */
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Save")
	TArray<uint8> OnSave();

	/** Restore state from a previously saved byte array. */
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Save")
	void OnLoad(const TArray<uint8>& Data);

	/** Returns the unique GameplayTag identifier for this persistable actor. */
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Save")
	FGameplayTag GetSaveTag() const;

	/** Returns true if this actor has changed since last save. */
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Save")
	bool NeedsSave() const;
};

// ============================================================================
// I_Toggleable — Objects with binary on/off states
// ============================================================================

UINTERFACE(MinimalAPI, BlueprintType)
class UToggleable : public UInterface
{
	GENERATED_BODY()
};

class PG_FRAMEWORK_API IToggleable
{
	GENERATED_BODY()

public:
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	void Toggle(AActor* Toggler);

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	void SetState(bool bNewState, AActor* Setter);

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	bool GetCurrentState() const;

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	FText GetStateLabel() const;

	/** Broadcast when state changes. */
	virtual void OnStateChanged(bool bNewState, AActor* Changer) {}
};

// ============================================================================
// I_Adjustable — Objects with continuous value range (dials, sliders)
// ============================================================================

UINTERFACE(MinimalAPI, BlueprintType)
class UAdjustable : public UInterface
{
	GENERATED_BODY()
};

class PG_FRAMEWORK_API IAdjustable
{
	GENERATED_BODY()

public:
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	void Adjust(float Delta, AActor* Adjuster);

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	void SetValue(float NewValue, AActor* Setter);

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	float GetCurrentValue() const;

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	float GetMinValue() const;

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
	float GetMaxValue() const;

	/** Broadcast when value changes. */
	virtual void OnValueChanged(float NewValue, AActor* Changer) {}
};
