// Copyright ExByte Studios. Item Interaction Ecosystem.

#pragma once

#include "CoreMinimal.h"
#include "GameplayTagContainer.h"
#include "ItemEnums.h"
#include "ItemInstanceData.h"
#include "InteractionTypes.generated.h"

class APlayerController;
class ACharacter;
class UInteractableComponent;
class UInventoryComponent;
class UTexture2D;

/**
 * Client -> server intent (section 9). The client never mutates state; it sends
 * this and the server re-validates everything before executing.
 */
USTRUCT(BlueprintType)
struct ITEMINTERACTION_API FInteractionRequest
{
	GENERATED_BODY()

	UPROPERTY(BlueprintReadWrite, Category = "Interaction")
	FGuid RequestId;

	UPROPERTY(BlueprintReadWrite, Category = "Interaction")
	EItemInteractionMode Mode = EItemInteractionMode::None;

	/** The verb that produced this request; lets the server pick the matching action. */
	UPROPERTY(BlueprintReadWrite, Category = "Interaction")
	FGameplayTag ActionTag;

	UPROPERTY(BlueprintReadWrite, Category = "Interaction")
	TObjectPtr<AActor> TargetActor = nullptr;

	UPROPERTY(BlueprintReadWrite, Category = "Interaction")
	FGuid ItemInstanceId;

	UPROPERTY(BlueprintReadWrite, Category = "Interaction")
	FGuid SourceContainerId;

	UPROPERTY(BlueprintReadWrite, Category = "Interaction")
	FGuid TargetContainerId;

	UPROPERTY(BlueprintReadWrite, Category = "Interaction")
	int32 TargetSlotIndex = INDEX_NONE;

	UPROPERTY(BlueprintReadWrite, Category = "Interaction")
	FGameplayTag TargetSlotTag;

	UPROPERTY(BlueprintReadWrite, Category = "Interaction")
	FTransform DesiredTransform = FTransform::Identity;

	UPROPERTY(BlueprintReadWrite, Category = "Interaction")
	int32 Quantity = 1;

	/** Last inventory revision the client had; lets the server detect desync. */
	UPROPERTY(BlueprintReadWrite, Category = "Interaction")
	int32 ClientRevision = 0;
};

/**
 * A single interaction the player could perform on the current target (section 8.4).
 * Built by the resolver, shown by the UI, and carries the ready-to-send Request.
 */
USTRUCT(BlueprintType)
struct ITEMINTERACTION_API FInteractionOption
{
	GENERATED_BODY()

	UPROPERTY(BlueprintReadOnly, Category = "Interaction")
	FGameplayTag ActionTag;

	UPROPERTY(BlueprintReadOnly, Category = "Interaction")
	EItemInteractionMode Mode = EItemInteractionMode::None;

	UPROPERTY(BlueprintReadOnly, Category = "Interaction")
	FText DisplayText;

	UPROPERTY(BlueprintReadOnly, Category = "Interaction")
	TObjectPtr<UTexture2D> Icon = nullptr;

	UPROPERTY(BlueprintReadOnly, Category = "Interaction")
	int32 Priority = 0;

	UPROPERTY(BlueprintReadOnly, Category = "Interaction")
	bool bRequiresHold = false;

	UPROPERTY(BlueprintReadOnly, Category = "Interaction")
	float HoldDuration = 0.f;

	/** Duration of the action itself once started (section 19). */
	UPROPERTY(BlueprintReadOnly, Category = "Interaction")
	float ActionDuration = 0.f;

	UPROPERTY(BlueprintReadOnly, Category = "Interaction")
	bool bIsEnabled = true;

	/** Why the option is greyed out, e.g. "Inventory Full", "Requires Wrench". */
	UPROPERTY(BlueprintReadOnly, Category = "Interaction")
	FText DisabledReason;

	UPROPERTY(BlueprintReadOnly, Category = "Interaction")
	FInteractionRequest Request;
};

/**
 * Everything an action/requirement needs to make a decision (section 17).
 * Assembled by the resolver on whichever machine is evaluating (client preview
 * or server validation).
 */
USTRUCT(BlueprintType)
struct ITEMINTERACTION_API FInteractionContext
{
	GENERATED_BODY()

	UPROPERTY(BlueprintReadOnly, Category = "Interaction")
	TObjectPtr<APlayerController> PlayerController = nullptr;

	UPROPERTY(BlueprintReadOnly, Category = "Interaction")
	TObjectPtr<ACharacter> Character = nullptr;

	UPROPERTY(BlueprintReadOnly, Category = "Interaction")
	TObjectPtr<AActor> TargetActor = nullptr;

	UPROPERTY(BlueprintReadOnly, Category = "Interaction")
	TObjectPtr<UInteractableComponent> TargetInteractable = nullptr;

	UPROPERTY(BlueprintReadOnly, Category = "Interaction")
	TObjectPtr<UInventoryComponent> PlayerInventory = nullptr;

	UPROPERTY(BlueprintReadOnly, Category = "Interaction")
	bool bHasHeldItem = false;

	UPROPERTY(BlueprintReadOnly, Category = "Interaction")
	FItemInstanceData HeldItem;

	/** The item the target itself represents (for pickups), if any. */
	UPROPERTY(BlueprintReadOnly, Category = "Interaction")
	bool bHasTargetItem = false;

	UPROPERTY(BlueprintReadOnly, Category = "Interaction")
	FItemInstanceData TargetItem;

	UPROPERTY(BlueprintReadOnly, Category = "Interaction")
	FGameplayTagContainer WorldTags;

	UPROPERTY(BlueprintReadOnly, Category = "Interaction")
	FVector HitLocation = FVector::ZeroVector;

	UPROPERTY(BlueprintReadOnly, Category = "Interaction")
	FVector HitNormal = FVector::ZeroVector;
};

/** Requirement type verbs (section 18). */
UENUM(BlueprintType)
enum class EInteractionRequirementType : uint8
{
	None,
	HasInventorySpace,
	HasItemWithTag,
	HasHeldItemWithTag,
	PropertyGreaterThan,
	PropertyLessThan,
	TargetHasFreeSlotTag,
	NotWet,
	NotBroken
};

/** One requirement gate on an interaction (section 18). */
USTRUCT(BlueprintType)
struct ITEMINTERACTION_API FInteractionRequirement
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interaction")
	EInteractionRequirementType RequirementType = EInteractionRequirementType::None;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interaction")
	FGameplayTag RequiredTag;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interaction")
	FName RequiredItemId;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interaction")
	float RequiredValue = 0.f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interaction")
	FText FailureText;
};

/** Timing / interruption data for an action (section 19). */
USTRUCT(BlueprintType)
struct ITEMINTERACTION_API FInteractionExecutionData
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interaction")
	bool bHasDuration = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interaction")
	float Duration = 0.f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interaction")
	bool bCanBeInterrupted = true;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interaction")
	bool bLockItemDuringAction = true;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interaction")
	bool bLockTargetDuringAction = false;
};
