// Copyright ExByte Studios. Item Interaction Ecosystem.

#include "ItemSaveLibrary.h"
#include "ItemInventoryLog.h"
#include "InventoryComponent.h"
#include "ItemDatabaseSubsystem.h"
#include "Kismet/GameplayStatics.h"

FInventorySaveData UItemSaveLibrary::CaptureInventory(UInventoryComponent* Inventory)
{
	FInventorySaveData Data;
	if (!Inventory)
	{
		return Data;
	}
	Inventory->GetAllItems(Data.Items);
	for (FItemInstanceData& Item : Data.Items)
	{
		Item.Lock.Clear(); // never persist transient locks (section 26)
	}
	Inventory->GetContainers(Data.Containers);
	return Data;
}

void UItemSaveLibrary::RestoreInventory(const UObject* WorldContext, UInventoryComponent* Inventory, const FInventorySaveData& Data)
{
	if (!Inventory || !Inventory->GetOwner() || !Inventory->GetOwner()->HasAuthority())
	{
		return;
	}

	Inventory->SetContainers(Data.Containers);
	Inventory->ClearAllItems();

	const UItemDatabaseSubsystem* DB = UItemDatabaseSubsystem::Get(WorldContext);
	for (const FItemInstanceData& Saved : Data.Items)
	{
		FItemInstanceData Item = Saved;
		if (DB) { DB->MigrateLoadedItem(Item); }
		Inventory->SetItemInSlot(Item, Item.CurrentContainerId, Item.SlotIndex);
	}
	UE_LOG(LogItemInventory, Log, TEXT("[Save] restored %d items into %s"), Data.Items.Num(), *GetNameSafe(Inventory->GetOwner()));
}

bool UItemSaveLibrary::SaveInventoryToSlot(UInventoryComponent* Inventory, const FString& SlotName, FName Key)
{
	if (!Inventory)
	{
		return false;
	}

	UItemSaveGame* Save = Cast<UItemSaveGame>(UGameplayStatics::LoadGameFromSlot(SlotName, 0));
	if (!Save)
	{
		Save = Cast<UItemSaveGame>(UGameplayStatics::CreateSaveGameObject(UItemSaveGame::StaticClass()));
	}
	if (!Save)
	{
		return false;
	}
	Save->Inventories.Add(Key, CaptureInventory(Inventory));
	return UGameplayStatics::SaveGameToSlot(Save, SlotName, 0);
}

bool UItemSaveLibrary::LoadInventoryFromSlot(const UObject* WorldContext, UInventoryComponent* Inventory, const FString& SlotName, FName Key)
{
	UItemSaveGame* Save = Cast<UItemSaveGame>(UGameplayStatics::LoadGameFromSlot(SlotName, 0));
	if (!Save)
	{
		return false;
	}
	const FInventorySaveData* Data = Save->Inventories.Find(Key);
	if (!Data)
	{
		return false;
	}
	RestoreInventory(WorldContext, Inventory, *Data);
	return true;
}
