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

#pragma once

#include "CoreMinimal.h"
#include "GameplayTagContainer.h"
#include "Subsystems/WorldSubsystem.h"
#include "LocationSubsystem.generated.h"

class ULocationData;

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnLocationChangedSignature, ULocationData*, Location);

/**
 * Single source of truth for which tagged locations the player currently occupies (GDD §10.4).
 * Fed by ALocationTrigger overlaps; queried + subscribed by everything else (session boundary,
 * commission location constraints, future shop entry). World-scoped and transient — nothing to save.
 *
 * Locations are identified by their ULocationData FGameplayTag, so they nest: while inside
 * Location.City.Beach the player also matches Location.City. The player can be in several at once.
 */
UCLASS()
class NAKEDDESIRE_API ULocationSubsystem : public UWorldSubsystem
{
	GENERATED_BODY()

public:
	// Reported by ALocationTrigger as the player enters / leaves a tagged volume.
	void EnterLocation(ULocationData* Location);
	void ExitLocation(ULocationData* Location);

	// True while the player occupies a location whose tag matches (or nests under) Query.
	UFUNCTION(BlueprintPure, Category = "Location")
	bool IsPlayerInLocation(FGameplayTag Query) const;

	UFUNCTION(BlueprintPure, Category = "Location")
	FGameplayTagContainer GetPlayerLocationTags() const { return ActiveTags; }

	// Most-specific current location (deepest tag) — for HUD / prompts. Null when outdoors / untagged.
	UFUNCTION(BlueprintPure, Category = "Location")
	ULocationData* GetCurrentLocation() const;

	UPROPERTY(BlueprintAssignable, Category = "Location")
	FOnLocationChangedSignature OnLocationEntered;

	UPROPERTY(BlueprintAssignable, Category = "Location")
	FOnLocationChangedSignature OnLocationExited;

private:
	void RebuildActiveTags();

	// Ref-counted: a location can be several overlapping trigger volumes, so we only fire enter on
	// 0->1 and exit on 1->0 — crossing between two boxes of the same place doesn't churn events.
	UPROPERTY()
	TMap<TObjectPtr<ULocationData>, int32> ActiveCounts;

	FGameplayTagContainer ActiveTags;
};