// © 2025 Naked People Team. All Rights Reserved.


#include "ClothingManager.h"
#include "ClothingItemDefinition.h"
#include "ClothingItemInstance.h"
#include "GameFramework/Character.h"
#include "Kismet/GameplayStatics.h"
#include "NakedDesire/Interactables/ItemPickup.h"
#include "NakedDesire/Player/NakedDesireCharacter.h"
#include "NakedDesire/SaveGame/GlobalSaveGameData.h"
#include "NakedDesire/SaveGame/ItemSaveRecord.h"
#include "NakedDesire/SaveGame/SaveSubsystem.h"

UClothingManager::UClothingManager()
{
	PrimaryComponentTick.bCanEverTick = false;
}

void UClothingManager::BeginPlay()
{
	Super::BeginPlay();
	
	HydrateClothing();
}

void UClothingManager::SetClothingSlotItem(const EClothingSlotType ClothingSlotType, UClothingItemInstance* ClothingItemInstance)
{
	if (ClothingItemInstance)
		EquippedClothing.Add(ClothingSlotType, ClothingItemInstance);
	else
		EquippedClothing.Remove(ClothingSlotType);
}

TArray<UClothingItemInstance*> UClothingManager::GetEquippedClothing() const
{
	TArray<TObjectPtr<UClothingItemInstance>> Items;
	EquippedClothing.GenerateValueArray(Items);
	return Items;
}

UClothingItemInstance* UClothingManager::GetSlotClothing(const EClothingSlotType SlotType)
{
	if (EquippedClothing.Contains(SlotType))
		return EquippedClothing[SlotType];
	
	return nullptr;
}

bool UClothingManager::IsBodyPartExposed(const EBodyPart BodyPart)
{
	for (const auto& [Key, Value] : EquippedClothing)
	{
		if (Value->GetClothingItemDefinition()->HiddenBodyParts.Contains(BodyPart))
			return false;
	}
	
	return true;
}

void UClothingManager::HydrateClothing()
{
	USaveSubsystem* SaveSubsystem = UGameplayStatics::GetGameInstance(GetWorld())->GetSubsystem<USaveSubsystem>();
	for (const FItemSaveRecord& ItemSaveRecord : SaveSubsystem->GetCurrentSave()->GetEquippedItems())
	{
		UClothingItemInstance* ClothingItemInstance = Cast<UClothingItemInstance>(UItemInstance::CreateFromRecord(this, ItemSaveRecord));
		if (!ClothingItemInstance)
			continue;

		PutOnClothing(ClothingItemInstance);
	}
}

float UClothingManager::GetHeelHeight()
{
	if (!EquippedClothing.Contains(EClothingSlotType::Footwear))
		return 0;
	
	const UClothingItemInstance* Footwear = EquippedClothing[EClothingSlotType::Footwear];
	
	return Footwear->GetClothingItemDefinition()->ShoesOffset;
}

void UClothingManager::SpawnClothingPickup(UClothingItemInstance* ItemInstance)
{
	if (!ItemPickupActor)
	{
		UE_LOG(LogTemp, Warning, TEXT("UClothingManager::SpawnClothingPickup ItemPickupActor is not set"));
		return;
	}

	AItemPickup* NewItemPickup = GetWorld()->SpawnActor<AItemPickup>(ItemPickupActor, GetOwner()->GetActorTransform());
	if (!NewItemPickup)
	{
		UE_LOG(LogTemp, Warning, TEXT("UClothingManager::SpawnClothingPickup NewItemPickup == nullptr"));
		return;
	}
	
	USaveSubsystem* SaveSubsystem = UGameplayStatics::GetGameInstance(GetWorld())->GetSubsystem<USaveSubsystem>();
	SaveSubsystem->GetCurrentSave()->AddWorldItem(ItemInstance, NewItemPickup->GetActorTransform());

	NewItemPickup->SetItem(ItemInstance);
}

void UClothingManager::PutOnClothing(UClothingItemInstance* ClothingItemInstance)
{
	if (!ClothingItemInstance)
		return;
	
	const EClothingSlotType ClothingSlotType = ClothingItemInstance->GetClothingItemDefinition()->SlotType;

	SetClothingSlotItem(ClothingSlotType, ClothingItemInstance);

	const UClothingItemDefinition* ClothingItem = ClothingItemInstance->GetClothingItemDefinition();
	if (ClothingItem->SlotType == EClothingSlotType::Bodysuit)
	{
		DropClothing(EClothingSlotType::Top);
		DropClothing(EClothingSlotType::Bottom);
		DropClothing(EClothingSlotType::UnderwearTop);
		DropClothing(EClothingSlotType::UnderwearBottom);
	}
	else if (ClothingItem->SlotType == EClothingSlotType::Top ||
		ClothingItem->SlotType == EClothingSlotType::Bottom ||
		ClothingItem->SlotType == EClothingSlotType::UnderwearTop ||
		ClothingItem->SlotType == EClothingSlotType::UnderwearBottom)
	{
		DropClothing(EClothingSlotType::Bodysuit);
	}

	OnClothingEquip.Broadcast(ClothingItemInstance);
}

void UClothingManager::TakeClothing(UClothingItemInstance* ClothingItemInstance)
{
	const EClothingSlotType SlotType = ClothingItemInstance->GetClothingItemDefinition()->SlotType;
	if (EquippedClothing.Contains(SlotType))
	{
		DropClothing(SlotType);
	}
	
	SetClothingSlotItem(SlotType, ClothingItemInstance);
	
	USaveSubsystem* SaveSubsystem = UGameplayStatics::GetGameInstance(GetWorld())->GetSubsystem<USaveSubsystem>();
	SaveSubsystem->GetCurrentSave()->AddEquippedItem(ClothingItemInstance);
	
	PutOnClothing(ClothingItemInstance);
}

UClothingItemInstance* UClothingManager::RemoveClothing(const EClothingSlotType ClothingSlotType)
{
	if (!EquippedClothing.Contains(ClothingSlotType))
		return nullptr;
	
	UClothingItemInstance* ExistingItem = EquippedClothing[ClothingSlotType];
	
	SetClothingSlotItem(ClothingSlotType, nullptr);

	OnClothingUnequip.Broadcast(ExistingItem);
	
	USaveSubsystem* SaveSubsystem = UGameplayStatics::GetGameInstance(GetWorld())->GetSubsystem<USaveSubsystem>();
	SaveSubsystem->GetCurrentSave()->RemoveEquippedItem(ExistingItem);
	
	return ExistingItem;
}

void UClothingManager::DropClothing(const EClothingSlotType ClothingType)
{
	UClothingItemInstance* ClothingItemInstance = RemoveClothing(ClothingType);
	if (!ClothingItemInstance)
		return;
	
	SpawnClothingPickup(ClothingItemInstance);

	OnClothingDropped.Broadcast(ClothingItemInstance);
}

bool UClothingManager::IsClothingTypeOn(const EClothingSlotType ClothingType)
{
	return EquippedClothing.Contains(ClothingType);
}
