// Copyright ExByte Studios. Item Interaction Ecosystem.

#include "ReplicatedInventoryList.h"
#include "InventoryComponent.h"

void FReplicatedInventoryList::PostReplicatedAdd(const TArrayView<int32>& AddedIndices, int32 /*FinalSize*/)
{
	if (!OwnerComponent)
	{
		return;
	}
	for (int32 Index : AddedIndices)
	{
		if (Entries.IsValidIndex(Index))
		{
			OwnerComponent->NotifyItemAdded(Entries[Index].Item);
		}
	}
	OwnerComponent->NotifyInventoryChanged();
}

void FReplicatedInventoryList::PostReplicatedChange(const TArrayView<int32>& /*ChangedIndices*/, int32 /*FinalSize*/)
{
	if (OwnerComponent)
	{
		OwnerComponent->NotifyInventoryChanged();
	}
}

void FReplicatedInventoryList::PreReplicatedRemove(const TArrayView<int32>& RemovedIndices, int32 /*FinalSize*/)
{
	if (!OwnerComponent)
	{
		return;
	}
	for (int32 Index : RemovedIndices)
	{
		if (Entries.IsValidIndex(Index))
		{
			OwnerComponent->NotifyItemRemoved(Entries[Index].Item);
		}
	}
	OwnerComponent->NotifyInventoryChanged();
}

FRepInventoryEntry& FReplicatedInventoryList::AddOrUpdate(const FGuid& Container, int32 Slot, const FItemInstanceData& Item)
{
	if (FRepInventoryEntry* Existing = FindByInstanceId(Item.InstanceId))
	{
		Existing->ContainerId = Container;
		Existing->SlotIndex = Slot;
		Existing->Item = Item;
		Existing->Item.CurrentContainerId = Container;
		Existing->Item.SlotIndex = Slot;
		MarkItemDirty(*Existing);
		return *Existing;
	}

	FRepInventoryEntry& New = Entries.Emplace_GetRef(Container, Slot, Item);
	New.Item.CurrentContainerId = Container;
	New.Item.SlotIndex = Slot;
	MarkItemDirty(New);
	return New;
}

bool FReplicatedInventoryList::RemoveByInstanceId(const FGuid& InstanceId)
{
	const int32 Index = Entries.IndexOfByPredicate([&InstanceId](const FRepInventoryEntry& E)
	{
		return E.Item.InstanceId == InstanceId;
	});
	if (Index == INDEX_NONE)
	{
		return false;
	}
	Entries.RemoveAt(Index);
	MarkArrayDirty();
	return true;
}

void FReplicatedInventoryList::MarkEntryDirtyByInstanceId(const FGuid& InstanceId)
{
	if (FRepInventoryEntry* Entry = FindByInstanceId(InstanceId))
	{
		MarkItemDirty(*Entry);
	}
}

FRepInventoryEntry* FReplicatedInventoryList::FindByInstanceId(const FGuid& InstanceId)
{
	return Entries.FindByPredicate([&InstanceId](const FRepInventoryEntry& E)
	{
		return E.Item.InstanceId == InstanceId;
	});
}

const FRepInventoryEntry* FReplicatedInventoryList::FindByInstanceId(const FGuid& InstanceId) const
{
	return Entries.FindByPredicate([&InstanceId](const FRepInventoryEntry& E)
	{
		return E.Item.InstanceId == InstanceId;
	});
}
