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


#include "PhoneWidgetController.h"
#include "GameFramework/Character.h"
#include "Faye/GameObjects/TimeOfDayActor.h"
#include "Faye/Interfaces/InventoryInterface.h"
#include "Faye/Inventory/BookItem.h"
#include "Faye/Inventory/Inventory.h"
#include "Faye/Inventory/Item.h"
#include "Faye/Inventory/ItemDatabase.h"
#include "Faye/Structs/BookDataStruct.h"
#include "Faye/System/FayeDeveloperSettings.h"
#include "Kismet/GameplayStatics.h"

void UPhoneWidgetController::InitializeController_Implementation()
{
	Super::InitializeController_Implementation();
	
	TimeOfDayActor = Cast<ATimeOfDayActor>(UGameplayStatics::GetActorOfClass(GetWorld(), ATimeOfDayActor::StaticClass()));
	TimeOfDayActor->OnTimeChanged.AddUniqueDynamic(this, &UPhoneWidgetController::OnTimeChanged);
	LastDayChecked = -1;
	
	const UFayeDeveloperSettings* DeveloperSettings = GetDefault<UFayeDeveloperSettings>();
	check(DeveloperSettings);
	ShopItemsData = DeveloperSettings->ShopListDataAsset.LoadSynchronous();
	
	GenerateShop();
}

bool UPhoneWidgetController::PurchaseSlot(int32 slotIndex)
{
	if (slotIndex < 0 || slotIndex > ItemsForSale.Num() - 1)
		return false;
	
	if (UInventory* Inventory = IInventoryInterface::Execute_GetInventory(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0)))
	{
		if (Inventory->ModifyGold(-ItemsForSale[slotIndex]->ItemSaleRowData.BaseCost))
		{
			ItemsForSale[slotIndex]->bSold = true;
			TArray<UItem*> Drops = GetBookDropsForSlot(ItemsForSale[slotIndex]);
			for (UItem* Drop : Drops)
			{
				Inventory->AddItem(Drop, 1);
			}
			return true;
		}
	}
	
	return false;
}

void UPhoneWidgetController::OnTimeChanged(FTimeChangedPayload TimeChangedPayload)
{
	// Refresh shop
	if (TimeOfDayActor->GetTime().GetDays() != LastDayChecked)
	{
		GenerateShop();
	}
}

void UPhoneWidgetController::GenerateShop()
{
	ItemsForSale.Empty();
	LastDayChecked = TimeOfDayActor->GetTime().GetDays();

	for (int32 i = 0; i < 8; i++)
	{
		int32 RandIndex = FMath::RandRange(0, ShopItemsData->SalesItemsList.Num() - 1);
		UItemSaleSlot* SlotObject = NewObject<UItemSaleSlot>();
		SlotObject->ItemSaleRowData = ShopItemsData->SalesItemsList[RandIndex];
		
		ItemsForSale.Add(SlotObject);
	}
}

TArray<UItem*> UPhoneWidgetController::GetBookDropsForSlot(const UItemSaleSlot* Slot) const
{
	TArray<UItem*> Drops;
	for (int32 i = 0; i < Slot->ItemSaleRowData.DropAmount; i++)
	{
		EBookCategory ChosenCategory = GetWeightedCategory(Slot->ItemSaleRowData.CategoryDropWeight);
		TArray<UBookItem*> BooksFromCategory = UItemDatabase::GetBooksFromCategory(GetWorld(), ChosenCategory);
		if (!BooksFromCategory.IsEmpty())
		{
			int32 RandIndex = FMath::RandRange(0, BooksFromCategory.Num() - 1);
			Drops.Add(BooksFromCategory[RandIndex]);
		}
	}
	return Drops;
}

EBookCategory UPhoneWidgetController::GetWeightedCategory(const TMap<EBookCategory, int32>& Weights)
{
	int32 TotalWeight = 0;
	
	for (const TPair<EBookCategory, int32>& Pair : Weights)
	{
		if (Pair.Value > 0)
		{
			TotalWeight += Pair.Value;
		}
	}
	
	// Fallback
	if (TotalWeight <= 0)
	{
		return EBookCategory::None;
	}
	
	int32 RandomValue = FMath::RandRange(1, TotalWeight);
	int32 RunningWeight = 0;
	for (const TPair<EBookCategory, int32>& Pair : Weights)
	{
		if (Pair.Value <= 0)
		{
			continue;
		}

		RunningWeight += Pair.Value;

		if (RandomValue <= RunningWeight)
		{
			return Pair.Key;
		}
	}
	return EBookCategory::None;
}
