// Copyright Pacificao. All Rights Reserved.

#include "AgrarianInventoryComponent.h"
#include "Net/UnrealNetwork.h"

UAgrarianInventoryComponent::UAgrarianInventoryComponent()
{
	PrimaryComponentTick.bCanEverTick = false;
	SetIsReplicatedByDefault(true);
}

void UAgrarianInventoryComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);
	DOREPLIFETIME(UAgrarianInventoryComponent, Items);
}

bool UAgrarianInventoryComponent::HasItem(FName ItemId, int32 Quantity) const
{
	return GetItemCount(ItemId) >= Quantity;
}

int32 UAgrarianInventoryComponent::GetItemCount(FName ItemId) const
{
	int32 Count = 0;
	for (const FAgrarianItemStack& Stack : Items)
	{
		if (Stack.ItemId == ItemId)
		{
			Count += Stack.Quantity;
		}
	}
	return Count;
}

float UAgrarianInventoryComponent::GetTotalWeight() const
{
	float TotalWeight = 0.0f;
	for (const FAgrarianItemStack& Stack : Items)
	{
		TotalWeight += FMath::Max(0.0f, Stack.UnitWeight) * FMath::Max(0, Stack.Quantity);
	}
	return TotalWeight;
}

bool UAgrarianInventoryComponent::AddItem(const FAgrarianItemStack& Stack)
{
	if (!GetOwner() || !GetOwner()->HasAuthority() || !Stack.IsValidStack())
	{
		return false;
	}

	for (FAgrarianItemStack& Existing : Items)
	{
		if (Existing.ItemId == Stack.ItemId)
		{
			Existing.Quantity += Stack.Quantity;
			BroadcastInventoryChanged();
			return true;
		}
	}

	if (Items.Num() >= MaxSlots)
	{
		return false;
	}

	Items.Add(Stack);
	BroadcastInventoryChanged();
	return true;
}

bool UAgrarianInventoryComponent::RemoveItem(FName ItemId, int32 Quantity)
{
	FAgrarianItemStack RemovedStack;
	return ExtractItem(ItemId, Quantity, RemovedStack);
}

bool UAgrarianInventoryComponent::ExtractItem(FName ItemId, int32 Quantity, FAgrarianItemStack& OutStack)
{
	OutStack = FAgrarianItemStack();

	if (!GetOwner() || !GetOwner()->HasAuthority() || Quantity <= 0 || !HasItem(ItemId, Quantity))
	{
		return false;
	}

	int32 Remaining = Quantity;
	for (int32 Index = Items.Num() - 1; Index >= 0 && Remaining > 0; --Index)
	{
		FAgrarianItemStack& Stack = Items[Index];
		if (Stack.ItemId != ItemId)
		{
			continue;
		}

		const int32 Removed = FMath::Min(Stack.Quantity, Remaining);
		if (OutStack.ItemId == NAME_None)
		{
			OutStack = Stack;
			OutStack.Quantity = 0;
		}

		OutStack.Quantity += Removed;
		Stack.Quantity -= Removed;
		Remaining -= Removed;

		if (Stack.Quantity <= 0)
		{
			Items.RemoveAt(Index);
		}
	}

	BroadcastInventoryChanged();
	return true;
}

bool UAgrarianInventoryComponent::SplitStackByIndex(int32 StackIndex, int32 SplitQuantity)
{
	if (!GetOwner() || !GetOwner()->HasAuthority() || SplitQuantity <= 0 || !Items.IsValidIndex(StackIndex) || Items.Num() >= MaxSlots)
	{
		return false;
	}

	FAgrarianItemStack& SourceStack = Items[StackIndex];
	if (!SourceStack.IsValidStack() || SplitQuantity >= SourceStack.Quantity)
	{
		return false;
	}

	FAgrarianItemStack SplitStack = SourceStack;
	SplitStack.Quantity = SplitQuantity;
	SourceStack.Quantity -= SplitQuantity;
	Items.Add(SplitStack);
	BroadcastInventoryChanged();
	return true;
}

void UAgrarianInventoryComponent::RestoreSavedItems(const TArray<FAgrarianItemStack>& SavedItems)
{
	if (!GetOwner() || !GetOwner()->HasAuthority())
	{
		return;
	}

	Items = SavedItems;
	BroadcastInventoryChanged();
}

void UAgrarianInventoryComponent::ServerAddItem_Implementation(const FAgrarianItemStack& Stack)
{
	AddItem(Stack);
}

void UAgrarianInventoryComponent::ServerRemoveItem_Implementation(FName ItemId, int32 Quantity)
{
	RemoveItem(ItemId, Quantity);
}

void UAgrarianInventoryComponent::ServerSplitStackByIndex_Implementation(int32 StackIndex, int32 SplitQuantity)
{
	SplitStackByIndex(StackIndex, SplitQuantity);
}

void UAgrarianInventoryComponent::OnRep_Items()
{
	BroadcastInventoryChanged();
}

void UAgrarianInventoryComponent::BroadcastInventoryChanged()
{
	OnInventoryChanged.Broadcast();
}
