// Copyright ExByte Studios. Item Interaction Ecosystem.

#pragma once

#include "CoreMinimal.h"
#include "Net/Serialization/FastArraySerializer.h"
#include "ItemInstanceData.h"
#include "ReplicatedInventoryList.generated.h"

class UInventoryComponent;

/**
 * One replicated item slot (section 7.3). The item carries its own ContainerId /
 * SlotIndex inside FItemInstanceData, but they are mirrored here so the FastArray
 * delta only needs the entry, and so clients can route OnRep callbacks per slot.
 */
USTRUCT()
struct ITEMINVENTORY_API FRepInventoryEntry : public FFastArraySerializerItem
{
	GENERATED_BODY()

	UPROPERTY()
	FGuid ContainerId;

	UPROPERTY()
	int32 SlotIndex = INDEX_NONE;

	UPROPERTY()
	FItemInstanceData Item;

	FRepInventoryEntry() = default;
	FRepInventoryEntry(const FGuid& InContainer, int32 InSlot, const FItemInstanceData& InItem)
		: ContainerId(InContainer), SlotIndex(InSlot), Item(InItem) {}
};

/**
 * FastArraySerializer carrying every item the inventory owns across all containers
 * (section 7.3 / 32). One list per component delta-replicates only changed entries.
 */
USTRUCT()
struct ITEMINVENTORY_API FReplicatedInventoryList : public FFastArraySerializer
{
	GENERATED_BODY()

	UPROPERTY()
	TArray<FRepInventoryEntry> Entries;

	/** Not replicated - set by the owning component so callbacks can broadcast. */
	UPROPERTY(NotReplicated)
	TObjectPtr<UInventoryComponent> OwnerComponent = nullptr;

	bool NetDeltaSerialize(FNetDeltaSerializeInfo& DeltaParms)
	{
		return FFastArraySerializer::FastArrayDeltaSerialize<FRepInventoryEntry, FReplicatedInventoryList>(Entries, DeltaParms, *this);
	}

	//~ FFastArraySerializer client callbacks
	void PostReplicatedAdd(const TArrayView<int32>& AddedIndices, int32 FinalSize);
	void PostReplicatedChange(const TArrayView<int32>& ChangedIndices, int32 FinalSize);
	void PreReplicatedRemove(const TArrayView<int32>& RemovedIndices, int32 FinalSize);

	// --- Server-side mutation helpers (mark dirty for delta replication) ---

	/** Adds or replaces the entry occupying (Container, Slot). Returns the live entry. */
	FRepInventoryEntry& AddOrUpdate(const FGuid& Container, int32 Slot, const FItemInstanceData& Item);

	/** Removes the entry with the given instance id. Returns true if one was removed. */
	bool RemoveByInstanceId(const FGuid& InstanceId);

	/** Marks an existing entry dirty after its Item was mutated in place. */
	void MarkEntryDirtyByInstanceId(const FGuid& InstanceId);

	FRepInventoryEntry* FindByInstanceId(const FGuid& InstanceId);
	const FRepInventoryEntry* FindByInstanceId(const FGuid& InstanceId) const;
};

template<>
struct TStructOpsTypeTraits<FReplicatedInventoryList> : public TStructOpsTypeTraitsBase2<FReplicatedInventoryList>
{
	enum
	{
		WithNetDeltaSerializer = true
	};
};
