// Copyright ExByte Studios. Item Interaction Ecosystem.

#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "InteractionTypes.h"
#include "ItemInteractionComponent.generated.h"

DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnInteractionResult, FGuid, RequestId, bool, bSuccess);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnOpenContainer, AActor*, ContainerActor);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnActionStarted, FGameplayTag, ActionTag, float, Duration);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnActionFinished, FGameplayTag, ActionTag, bool, bCompleted);

/** Replicated snapshot of a long/hold action in progress (section 19), for UI. */
USTRUCT(BlueprintType)
struct FActiveInteractionState
{
	GENERATED_BODY()

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

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

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

/**
 * Player-side hub that turns a chosen option into a server request and executes
 * the authorized result (sections 9, 25). Attach to the player pawn alongside
 * an InventoryComponent and (optionally) an InteractionTraceComponent.
 *
 * Flow: UI/input picks an FInteractionOption -> RequestInteraction() -> Server RPC
 * -> server re-resolves and re-validates -> executes the transaction -> state
 * replicates back. The client never changes item state itself.
 */
UCLASS(ClassGroup = (Interaction), meta = (BlueprintSpawnableComponent))
class ITEMINTERACTION_API UItemInteractionComponent : public UActorComponent
{
	GENERATED_BODY()

public:
	UItemInteractionComponent();

	virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;

	/** Client entry point: send the chosen option's request to the server. */
	UFUNCTION(BlueprintCallable, Category = "Interaction")
	void RequestInteraction(const FInteractionOption& Option);

	/** Client: signal that a hold action's button was released (cancels if mid-action). */
	UFUNCTION(BlueprintCallable, Category = "Interaction")
	void ReleaseHold();

	/** Server: cancel any action in progress (bind to damage/stun for interruption). */
	UFUNCTION(BlueprintCallable, Category = "Interaction")
	void CancelActiveAction();

	UFUNCTION(BlueprintPure, Category = "Interaction")
	const FActiveInteractionState& GetActiveAction() const { return ActiveAction; }

	/** Lower-level entry: send a hand-built request. */
	UFUNCTION(BlueprintCallable, Category = "Interaction")
	void SendRequest(const FInteractionRequest& Request);

	// --- Inventory UI operations (section 23.3). Client calls, server validates. ---

	/**
	 * Move/transfer an item. StorageActor == null -> rearrange within the player's
	 * own inventory. Otherwise transfer between the player and the storage actor's
	 * inventory (loot). ToContainerId == invalid -> first accepting container.
	 */
	UFUNCTION(BlueprintCallable, Category = "Inventory")
	void RequestMoveItem(AActor* StorageActor, FGuid InstanceId, FGuid ToContainerId, int32 ToSlot);

	UFUNCTION(BlueprintCallable, Category = "Inventory")
	void RequestSplitStack(FGuid InstanceId, int32 Amount);

	UFUNCTION(BlueprintCallable, Category = "Inventory")
	void RequestMergeStack(FGuid SourceInstanceId, FGuid TargetInstanceId);

	UFUNCTION(BlueprintCallable, Category = "Inventory")
	void RequestDropFromInventory(FGuid InstanceId);

	UPROPERTY(BlueprintAssignable, Category = "Interaction")
	FOnInteractionResult OnInteractionResult;

	/** Fired locally when the player chooses to open a container - UI opens the loot window. */
	UPROPERTY(BlueprintAssignable, Category = "Interaction")
	FOnOpenContainer OnOpenContainer;

	UPROPERTY(BlueprintAssignable, Category = "Interaction")
	FOnActionStarted OnActionStarted;

	UPROPERTY(BlueprintAssignable, Category = "Interaction")
	FOnActionFinished OnActionFinished;

	/** Max slack (cm) added to the interactable's own distance when server-validating. */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Interaction")
	float ServerDistanceTolerance = 75.f;

protected:
	UFUNCTION(Server, Reliable)
	void Server_RequestInteraction(const FInteractionRequest& Request);

	UFUNCTION(Server, Reliable)
	void Server_MoveItem(AActor* StorageActor, FGuid InstanceId, FGuid ToContainerId, int32 ToSlot);

	UFUNCTION(Server, Reliable)
	void Server_SplitStack(FGuid InstanceId, int32 Amount);

	UFUNCTION(Server, Reliable)
	void Server_MergeStack(FGuid SourceInstanceId, FGuid TargetInstanceId);

	UFUNCTION(Server, Reliable)
	void Server_DropFromInventory(FGuid InstanceId);

	UFUNCTION(Server, Reliable)
	void Server_ReleaseHold();

	UFUNCTION(Client, Reliable)
	void Client_InteractionResult(FGuid RequestId, bool bSuccess);

	/** Server hook for dropping an item into the world. Overridden in ItemWorld. */
	virtual bool HandleDropFromInventory(FGuid InstanceId);

private:
	/** Server: full validation pipeline (section 9). Returns the authorized option. */
	bool AuthorizeRequest(const FInteractionRequest& Request, FInteractionContext& OutContext, FInteractionOption& OutOption) const;

public:
	/**
	 * Server: run a mode directly from an already-built context (used by the named
	 * UInteractionAction_* classes so they share the one execution path). Builds a
	 * minimal option/request and dispatches through ExecuteAuthorized (virtual, so
	 * the ItemWorld subclass handles carry/equip/install/use).
	 */
	bool ServerExecuteMode(const FInteractionContext& Context, EItemInteractionMode Mode, FGameplayTag ActionTag);

protected:
	APawn* GetPawn() const;

	/**
	 * Server: run the authorized option's effect. Virtual so ItemWorld can add the
	 * carry/drop/equip/install/use-on-target modes (which need ItemWorld types)
	 * without ItemInteraction depending on ItemWorld. Base handles pickup + transfer.
	 */
	virtual bool ExecuteAuthorized(const FInteractionContext& Context, const FInteractionOption& Option, const FInteractionRequest& Request);

	bool ExecutePickup(const FInteractionContext& Context);
	bool ExecuteTransfer(const FInteractionContext& Context, const FInteractionRequest& Request);
	bool ExecuteActionClass(const FInteractionContext& Context, const FInteractionOption& Option);

	// --- Timed / hold action plumbing (section 19) ---
	void BeginTimedAction(const FInteractionContext& Context, const FInteractionOption& Option, const FInteractionRequest& Request);
	void CompleteTimedAction();
	void AbortTimedAction();
	void LockActionItem(bool bLock);

	UPROPERTY(ReplicatedUsing = OnRep_ActiveAction)
	FActiveInteractionState ActiveAction;

	UFUNCTION()
	void OnRep_ActiveAction();

	// Server-side pending state.
	bool bHasPending = false;
	bool bPendingHold = false;
	float PendingEndTime = 0.f;
	float PendingMaxDistanceSq = 0.f;
	FInteractionContext PendingContext;
	FInteractionOption PendingOption;
	FInteractionRequest PendingRequest;
};
