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

#pragma once

#include "CoreMinimal.h"
#include "NPCType.h"
#include "Subsystems/WorldSubsystem.h"
#include "NakedDesire/Global/TimeOfDaySubsystem.h"
#include "NPCDirectorSubsystem.generated.h"

class ANPC;
class APawn;
class UNPCDirectorConfig;

/**
 * The GDD §17.1 NPCManager: single authority for the crowd around the player (§10.2, §19).
 * A WorldSubsystem (like UMissionSubsystem / UTimeOfDaySubsystem) — it needs world access plus the
 * day/night phase to drive density.
 *
 * Keeps a pool of NPC actors prewarmed from UNPCDirectorConfig::SpawnTable and, on a light timer,
 * reconciles the live population: recycles NPCs past the despawn radius and activates pooled ones at
 * NavMesh points in the spawn ring until the phase-appropriate target count is met. Mesh-agnostic —
 * it never touches what an NPC looks like, only how many exist and where. Supersedes the BP spawner.
 */
UCLASS()
class NAKEDDESIRE_API UNPCDirectorSubsystem : public UWorldSubsystem
{
	GENERATED_BODY()

public:
	virtual void OnWorldBeginPlay(UWorld& InWorld) override;
	virtual void Deinitialize() override;

private:
	UFUNCTION()
	void HandlePhaseChanged(EDayPhase NewPhase);

	void PrewarmPool();
	void UpdatePopulation();            // timer-driven reconcile
	int32 CurrentTargetCount() const;

	ANPC* TakeFromPool();
	void ReturnToPool(ANPC* NPC);
	ENPCType PickWeightedClass() const;
	bool FindSpawnPoint(const FVector& Around, FVector& OutLocation);
	TSubclassOf<ANPC> GetRandomNPCClass(TArray<TSubclassOf<ANPC>> InNPCClasses);
	void CorrectSpawnLocation(FVector& OutVector);

	APawn* GetPlayerPawn() const;
	UNPCDirectorConfig* GetConfig() const;

	// Inactive (hidden) NPCs ready to activate.
	UPROPERTY()
	TArray<TObjectPtr<ANPC>> Pool;

	// Currently live NPCs around the player.
	UPROPERTY()
	TArray<TObjectPtr<ANPC>> Active;

	FTimerHandle UpdateTimerHandle;
	EDayPhase CachedPhase = EDayPhase::Day;
};