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


#include "BPFL_EpicInventory.h"
#include "AC_PlayerInventory.h"
#include "AC_InventoryItem.h"
#include "AC_PlayerStats.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "GameFramework/Character.h"


//Returns the player's Inventory Component
UAC_PlayerInventory* UBPFL_EpicInventory::GetPlayerInventoryComponent(UObject* WorldContextObject)
{
	UAC_PlayerInventory* PlayerInventoryComponent(nullptr);

	APlayerController* PlayerController = WorldContextObject->GetWorld()->GetFirstPlayerController();

	if (PlayerController)
	{
		APawn* PlayerPawn = PlayerController->GetPawn();

		if (PlayerPawn)
		{
			PlayerInventoryComponent = PlayerPawn->FindComponentByClass<UAC_PlayerInventory>();
		}
	}


	return PlayerInventoryComponent;
}

void UBPFL_EpicInventory::RequestInteraction(AActor* InteractingActor)
{
	UAC_PlayerInventory* PlayerInventoryComponent = GetPlayerInventoryComponent(InteractingActor);
	UAC_InventoryItem* ObjectInventoryItem = InteractingActor->FindComponentByClass<UAC_InventoryItem>();
	TArray<FStartingItems> ObjectItemInfoArray = ObjectInventoryItem->ItemInformation;
	UAC_PlayerStats* PlayerStatsComponent = GetPlayerStatsComponent(InteractingActor);
	APawn* PlayerPawn = InteractingActor->GetWorld()->GetFirstPlayerController()->GetPawn();
	ACharacter* PlayerCharacter = Cast<ACharacter>(PlayerPawn);
	EInventoryCapType PlayerCapType = PlayerInventoryComponent->GetInventoryCapType();
	if (PlayerInventoryComponent)
	{
		if (PlayerInventoryComponent->bUseInventoryCap)
		{
			//Check type of cap and if there is room then add item
			UE_LOG(LogTemp, Warning, TEXT("Implement cap check"));
			switch (PlayerCapType)
			{
			case EInventoryCapType::None:
				for (const FStartingItems& DTRow : ObjectItemInfoArray)
				{
					FBaseItemInfo* LocItemInfo = DTRow.ItemDataTableAndRow.DataTable->FindRow<FBaseItemInfo>(DTRow.ItemDataTableAndRow.RowName, FString("Interaction Request"));
					int32 LocItemQuantity = DTRow.QuantityOfItem;
					PlayerInventoryComponent->RequestAddItem(*LocItemInfo, LocItemQuantity, InteractingActor);
					UE_LOG(LogTemp, Warning, TEXT("Attempted Add"));
					

				}
				break;
			case EInventoryCapType::Weight:
				for (int32 i = 0; i < ObjectItemInfoArray.Num(); i++)
				{
					FBaseItemInfo* LocItemInfo = ObjectItemInfoArray[i].ItemDataTableAndRow.DataTable->FindRow<FBaseItemInfo>(ObjectItemInfoArray[i].ItemDataTableAndRow.RowName, FString("Interaction Request"));
					int32 LocItemQuantity = ObjectItemInfoArray[i].QuantityOfItem;
					float LocItemWeight = LocItemInfo->ItemWeight;
					float LocMaxCarryWeight = PlayerStatsComponent->MaxCarryWeight;
					float LocCurrentCarryWeight = PlayerStatsComponent->CurrentCarryWeight;

					if ((LocItemWeight + LocCurrentCarryWeight) >= LocMaxCarryWeight)
					{
						//Item will encumber player so trigger encumberance as well
						PlayerInventoryComponent->RequestAddItem(*LocItemInfo, LocItemQuantity, InteractingActor);
						PlayerStatsComponent->UpdateCurrentCarryWeight();
						UCharacterMovementComponent* MovementComponent = PlayerCharacter->GetCharacterMovement();
						MovementComponent->MaxWalkSpeed = 75.0f;
						
						UE_LOG(LogTemp, Warning, TEXT("Weight method used"));

					}
					else if ((LocItemWeight + LocCurrentCarryWeight) < LocMaxCarryWeight)
					{
						//Item will not encumber player so only add item and update weight
						PlayerInventoryComponent->RequestAddItem(*LocItemInfo, LocItemQuantity, InteractingActor);
						PlayerStatsComponent->UpdateCurrentCarryWeight();
						
						UE_LOG(LogTemp, Warning, TEXT("Weight method used"));

					}
					else {
						//Item will neither encumber or not encumber player somehow so add item and update weight
						PlayerInventoryComponent->RequestAddItem(*LocItemInfo, LocItemQuantity, InteractingActor);
						PlayerStatsComponent->UpdateCurrentCarryWeight();
						
						UE_LOG(LogTemp, Warning, TEXT("Weight method used"));
					}

				}
				break;
			case EInventoryCapType::TotalItems:
				for (int32 i = 0; i < ObjectItemInfoArray.Num(); i++)
				{
					FBaseItemInfo* LocItemInfo = ObjectItemInfoArray[i].ItemDataTableAndRow.DataTable->FindRow<FBaseItemInfo>(ObjectItemInfoArray[i].ItemDataTableAndRow.RowName, FString("Interaction Request"));
					int32 LocItemQuantity = ObjectItemInfoArray[i].QuantityOfItem;
					int32 LocMaxItemCapacity = PlayerInventoryComponent->InventoryMaxCapacity;
					int32 LocCurrentItemCapacity = PlayerInventoryComponent->InventoryCurrentCapacity;

					if ((LocItemQuantity + LocCurrentItemCapacity) > LocMaxItemCapacity)
					{
						//Would make capacity over max so do not add
						UE_LOG(LogTemp, Warning, TEXT("Thought it was too much"));
					}
					else if ((LocItemQuantity + LocCurrentItemCapacity) <= LocMaxItemCapacity)
					{
						//Would not go over max capacity so add item
						PlayerInventoryComponent->RequestAddItem(*LocItemInfo, LocItemQuantity, InteractingActor);
						UE_LOG(LogTemp, Warning, TEXT("Attempted Add"));
						
					}
					else {
						//Some weird edgcase where it would not exeed or be less than
						PlayerInventoryComponent->RequestAddItem(*LocItemInfo, LocItemQuantity, InteractingActor);
						UE_LOG(LogTemp, Warning, TEXT("Attempted Add"));
						

					}
				}
				break;
			case EInventoryCapType::TotalItemsPerCategory:
				for (int32 i = 0; i < ObjectItemInfoArray.Num(); i++)
				{
					FBaseItemInfo* LocItemInfo = ObjectItemInfoArray[i].ItemDataTableAndRow.DataTable->FindRow<FBaseItemInfo>(ObjectItemInfoArray[i].ItemDataTableAndRow.RowName, FString("Interaction Request"));
					int32 LocItemQuantity = ObjectItemInfoArray[i].QuantityOfItem;
					TMap<EItemType, int32> LocInventoryCapacityMap = PlayerInventoryComponent->InventoryCapacityPerCategory;
					EItemType LocItemType = LocItemInfo->ItemType;
					int32* LocCategoryMaxCapacity = LocInventoryCapacityMap.Find(LocItemType);
					int32 LocCategoryCurrentCapacity = PlayerInventoryComponent->GetAllInventoryItemsInCategory(LocItemType).Num();
					if ((LocItemQuantity + LocCategoryCurrentCapacity) > *LocCategoryMaxCapacity)
					{
						//Item would exceed category max so do not add
					}
					else if ((LocItemQuantity + LocCategoryCurrentCapacity) <= *LocCategoryMaxCapacity)
					{
						//Item would not exceed category max so add and update capacity
						PlayerInventoryComponent->RequestAddItem(*LocItemInfo, LocItemQuantity, InteractingActor);
						
					}

				}
				break;
			default:
				UE_LOG(LogTemp, Warning, TEXT("Default Case Entered"));
				break;
			}
			
		}
		else {
			// Add item for each item defined in the item array on the component
			for (const FStartingItems& DTRow : ObjectItemInfoArray)
			{
				FBaseItemInfo* LocItemInfo = DTRow.ItemDataTableAndRow.DataTable->FindRow<FBaseItemInfo>(DTRow.ItemDataTableAndRow.RowName, FString("Interaction Request"));
				int32 LocItemQuantity = DTRow.QuantityOfItem;
				PlayerInventoryComponent->RequestAddItem(*LocItemInfo, LocItemQuantity, InteractingActor);
				UE_LOG(LogTemp, Warning, TEXT("Attempted Add"));
				
				
			}
			
			
		}
		
		
	}

}

UAC_PlayerStats* UBPFL_EpicInventory::GetPlayerStatsComponent(UObject* WorldContextObject)
{
	UAC_PlayerStats* PlayerStatsComponent(nullptr);

	APawn* PlayerPawn = WorldContextObject->GetWorld()->GetFirstPlayerController()->GetPawn();
	if (PlayerPawn)
	{
		PlayerStatsComponent = PlayerPawn->FindComponentByClass<UAC_PlayerStats>();
		if (PlayerStatsComponent)
		{
			return PlayerStatsComponent;
		}
		else {
			return PlayerStatsComponent;
		}
	}
	else {
		return PlayerStatsComponent;
	}
}

bool UBPFL_EpicInventory::AreItemsEqual(const FBaseItemInfo& ItemA, const FBaseItemInfo& ItemB)
{
	bool ItemsEqual = false;

	if (ItemA == ItemB)
	{
		ItemsEqual = true;
	}

	return ItemsEqual;
}

