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

#pragma once

#include "CoreMinimal.h"
#include "Subsystems/GameInstanceSubsystem.h"
#include "InventorySubsystem.generated.h"

class UItemInstance;
class UClothingManager;
class UGlobalSaveGameData;
class UPhoneItemInstance;

DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnWardrobeChangedSignature);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnPhoneChangedSignature, UPhoneItemInstance*, Phone);

/**
 * Runtime owner of the off-body item store (the apartment wardrobe, GDD §6.5 / §10.4).
 *
 * Holds live UItemInstance objects mirrored from UGlobalSaveGameData::WardrobeItems and is
 * the single entry point for moving items between the wardrobe and the body. Equipped items
 * stay owned by the per-character UClothingManager (it remains the body-state authority and
 * keeps writing the EquippedItems bucket); this subsystem orchestrates the wardrobe<->equipped
 * transfer so the two save buckets can never drift. Mutations broadcast OnWardrobeChanged so
 * the wardrobe UI can refresh without polling.
 */
UCLASS()
class NAKEDDESIRE_API UInventorySubsystem : public UGameInstanceSubsystem
{
	GENERATED_BODY()

public:
	UPROPERTY(BlueprintAssignable)
	FOnWardrobeChangedSignature OnWardrobeChanged;

	// Fires when the phone slot changes; broadcasts the newly-equipped phone, or nullptr when emptied.
	UPROPERTY(BlueprintAssignable)
	FOnPhoneChangedSignature OnPhoneChanged;

	/** Live wardrobe instances (off-body, mirrored from the save). */
	const TArray<TObjectPtr<UItemInstance>>& GetWardrobeItems();

	/** The phone occupying the dedicated phone slot (§6.5 / §9.9), or nullptr if none is equipped. */
	UPhoneItemInstance* GetEquippedPhone();

	/** Bring an item into the wardrobe (purchase, world-return). */
	void AddToWardrobe(UItemInstance* Item);

	/** Remove an item from the wardrobe without equipping it (discard). */
	void RemoveFromWardrobe(UItemInstance* Item);

	/** Move a stored item onto the body; any displaced garment returns to the wardrobe. */
	void EquipFromWardrobe(UItemInstance* Item);

	/** Take an equipped garment off the body and store it back in the wardrobe. */
	void UnequipToWardrobe(UItemInstance* Item);

private:
	void EnsureHydrated();
	void StoreItem(UItemInstance* Item);    // live list + save bucket, no broadcast
	void UnstoreItem(UItemInstance* Item);  // live list + save bucket, no broadcast

	void EquipPhone(UPhoneItemInstance* Phone);    // hot-swaps the previous phone back to the wardrobe
	void UnequipPhone(UPhoneItemInstance* Phone);  // stores the phone back in the wardrobe

	UClothingManager* GetPlayerClothingManager() const;
	UGlobalSaveGameData* GetSave() const;

	UPROPERTY()
	TArray<TObjectPtr<UItemInstance>> WardrobeItems;

	UPROPERTY()
	TObjectPtr<UPhoneItemInstance> EquippedPhone;

	// The save the live list was built from; re-hydrate when this changes (e.g. load game).
	TWeakObjectPtr<UGlobalSaveGameData> HydratedSave;
};