// Fill out your copyright notice in the Description page of Project Settings.


#include "ItemDatabase.h"

#include "Faye/Data/Filters/ItemFilters.h"
#include "Faye/System/FayeDeveloperSettings.h"
#include "Kismet/KismetStringLibrary.h"

void UItemDatabase::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);
	
	Authors.Empty();
	if (const UFayeDeveloperSettings* Settings = GetDefault<UFayeDeveloperSettings>())
	{
		if (const UDataTable* DataTable = Cast<UDataTable>(Settings->BooksDataTable.LoadSynchronous()))
		{
			DataTable->ForeachRow<FBookDataStructRow>(TEXT(""), [&](const FName& RowName, const FBookDataStructRow& Row)
			{
				if (!Row.ItemName.IsEmpty())
				{
					UBookItem* BookItem = NewObject<UBookItem>(this);
					int32 ID = UKismetStringLibrary::Conv_StringToInt(RowName.ToString());
					BookItem->SetupBook(Row, ID);
					check(!LoadedBooksMap.Contains(BookItem->ItemId));
					LoadedBooksMap.Add(BookItem->ItemId, BookItem);
					
					if (FBookCategoryMap* MapEntry = BooksByCategoryMap.Find(BookItem->BookCategory))
					{
						MapEntry->Books.Add(BookItem);
					}
					else
					{
						FBookCategoryMap NewMapEntry;
						NewMapEntry.Books.Add(BookItem);
						BooksByCategoryMap.Add(BookItem->BookCategory, NewMapEntry);
					}
					Authors.Add(BookItem->Author);
					AllBooks.Add(BookItem);
					if (BookItem->PublicationDate <= EarliestPublicationDate)
					{
						EarliestPublicationDate = BookItem->PublicationDate;
					}
					if (BookItem->PublicationDate >= LatestPublicationDate)
					{
						LatestPublicationDate = BookItem->PublicationDate;
					}
				}
			});
		}
	}
}

UItemDatabase* UItemDatabase::Get(const UObject* WorldContext)
{
	if (!WorldContext || !WorldContext->GetWorld())
		return nullptr;
	
	return WorldContext->GetWorld()->GetGameInstance()->GetSubsystem<UItemDatabase>();
}

UBookItem* UItemDatabase::GetBook(const UObject* WorldContext, int32 Id)
{
	if (!WorldContext || !WorldContext->GetWorld() || Id <= -1)
		return nullptr;
	
	if (UItemDatabase* ItemDb = WorldContext->GetWorld()->GetGameInstance()->GetSubsystem<UItemDatabase>())
	{
		if (ItemDb->LoadedBooksMap.Contains(Id))
		{
			return ItemDb->LoadedBooksMap[Id];
		}
	}
	return nullptr;
}

TArray<UBookItem*> UItemDatabase::GetBooksFromCategory(const UObject* WorldContext, EBookCategory Category)
{
	TArray<UBookItem*> GatheredBooks;
	if (!WorldContext || !WorldContext->GetWorld() || Category == EBookCategory::None)
		return GatheredBooks;
	
	if (UItemDatabase* ItemDb = WorldContext->GetWorld()->GetGameInstance()->GetSubsystem<UItemDatabase>())
	{
		if (const FBookCategoryMap* MapEntry = ItemDb->BooksByCategoryMap.Find(Category))
		{
			return MapEntry->Books;
		}
	}
	return GatheredBooks;
}

TArray<FText> UItemDatabase::GetAuthorList(const UObject* WorldContext)
{
	if (!WorldContext || !WorldContext->GetWorld())
		return TArray<FText>();
	
	if (UItemDatabase* ItemDb = WorldContext->GetWorld()->GetGameInstance()->GetSubsystem<UItemDatabase>())
	{
		return ItemDb->Authors;
	}
	
	return TArray<FText>();
}

TArray<UItem*> UItemDatabase::FilterItems(const UObject* WorldContext, const UItemFilter* Filter)
{
	TArray<UItem*> Temp;
	if (!WorldContext || !WorldContext->GetWorld())
		return Temp;
	
	if (UItemDatabase* ItemDb = WorldContext->GetWorld()->GetGameInstance()->GetSubsystem<UItemDatabase>())
	{
		Temp = ItemDb->AllBooks;
		FilterItemArray(Filter, Temp);
	}

	return Temp;
}

void UItemDatabase::FilterItemArray(const UItemFilter* Filter, TArray<UItem*>& ItemList)
{
	for (auto It = ItemList.CreateIterator(); It; ++It)
	{
		if (!Filter->Pass(*It))
			It.RemoveCurrent();
	}
}

const TArray<UItem*>& UItemDatabase::GetAllBooks(const UObject* WorldContext)
{
	return Get(WorldContext)->AllBooks;
}

