// Copyright Ngonart OU. All Rights Reserved.
// UE5 Modular Game Framework — SS_PlanarCaptureManager (138)
// Global budget manager for all planar capture surfaces in the world.
//
// One instance per World (World Subsystem). Each frame, scores every registered
// capture surface by distance, screen coverage, facing angle, and scripted priority.
// Assigns quality tiers across all surfaces respecting a global budget
// (max simultaneous high-quality captures, max total render target memory).
// Forces idle/disabled state on surfaces outside active rooms/sublevels.
//
// Also manages the render target pool — allocates, reuses, and resizes RTs
// to minimize memory churn.

#pragma once

#include "CoreMinimal.h"
#include "Subsystems/WorldSubsystem.h"
#include "Tickable.h"
#include "Misc/Optional.h"
#include "Capture/PlanarCaptureCommon.h"
#include "SS_PlanarCaptureManager.generated.h"

class ABP_PlanarCaptureActor;
class UBPC_PlanarCapture;

// Delegates
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnSurfaceRegistered, ABP_PlanarCaptureActor*, Surface, int32, TotalSurfaces);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnSurfaceUnregistered, ABP_PlanarCaptureActor*, Surface, int32, TotalSurfaces);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnGlobalQualityCapChanged, EPlanarCaptureQualityTier, NewCap);

/**
 * SS_PlanarCaptureManager — Global Planar Capture Budget Manager.
 *
 * Manages all ABP_PlanarCaptureActor instances per world. Evaluates priority
 * and assigns quality tiers to stay within a configurable budget.
 * Also owns the render target pool to reduce memory allocation overhead.
 *
 * Multiplayer: This subsystem exists on both server and clients.
 * On the server, it tracks surfaces for replication state.
 * On clients, it drives actual capture rendering.
 */
UCLASS()
class PG_FRAMEWORK_API USS_PlanarCaptureManager : public UWorldSubsystem, public FTickableGameObject
{
	GENERATED_BODY()

public:
	USS_PlanarCaptureManager();

	// ========================================================================
	// Lifecycle
	// ========================================================================

	virtual void Initialize(FSubsystemCollectionBase& Collection) override;
	virtual void Deinitialize() override;

	// FTickableGameObject
	virtual void Tick(float DeltaTime) override;
	virtual TStatId GetStatId() const override;
	virtual bool IsTickable() const override { return !IsTemplate(); }
	virtual bool IsTickableInEditor() const override { return false; }
	virtual UWorld* GetTickableGameObjectWorld() const override { return GetWorld(); }

	// ========================================================================
	// Surface Registry
	// ========================================================================

	/**
	 * Register a capture surface actor with the global manager.
	 * Called by ABP_PlanarCaptureActor::BeginPlay.
	 */
	UFUNCTION(BlueprintCallable, Category = "Capture|Manager")
	void RegisterSurface(ABP_PlanarCaptureActor* Surface);

	/**
	 * Unregister a capture surface actor. Called on EndPlay.
	 */
	UFUNCTION(BlueprintCallable, Category = "Capture|Manager")
	void UnregisterSurface(ABP_PlanarCaptureActor* Surface);

	/**
	 * Get all currently registered surfaces.
	 */
	UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Capture|Manager")
	TArray<ABP_PlanarCaptureActor*> GetRegisteredSurfaces() const;

	/**
	 * Get the number of registered surfaces.
	 */
	UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Capture|Manager")
	int32 GetSurfaceCount() const { return RegisteredSurfaces.Num(); }

	// ========================================================================
	// Quality Budget Management
	// ========================================================================

	/**
	 * Global quality ceiling — caps all surfaces at this tier regardless of score.
	 * Use this for lower-end hardware targets.
	 */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Capture|Manager|Budget")
	EPlanarCaptureQualityTier GlobalQualityCap = EPlanarCaptureQualityTier::High;

	/**
	 * Maximum number of simultaneous Hero-tier captures.
	 */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Capture|Manager|Budget")
	int32 MaxHeroSurfaces = 1;

	/**
	 * Maximum number of simultaneous High-tier captures.
	 */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Capture|Manager|Budget")
	int32 MaxHighSurfaces = 3;

	/**
	 * Maximum number of simultaneous Medium-tier captures.
	 */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Capture|Manager|Budget")
	int32 MaxMediumSurfaces = 6;

	/**
	 * Maximum total render target memory in megabytes across all surfaces.
	 */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Capture|Manager|Budget")
	float MaxTotalRenderTargetMemoryMB = 128.0f;

	/**
	 * Distance at which capture quality drops to Off (world units).
	 */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Capture|Manager|Budget")
	float MaxCaptureDistance = 10000.0f;

	/**
	 * Interval between full re-evaluation of all surfaces (seconds).
	 * Individual surfaces check their own interval every frame via their component.
	 */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Capture|Manager|Budget")
	float FullEvaluationInterval = 0.5f;

	// ========================================================================
	// Render Target Pool
	// ========================================================================

	/**
	 * Request a render target from the pool. Returns nullptr if none available.
	 */
	UTextureRenderTarget2D* RequestRenderTarget(int32 Size);

	/**
	 * Release a render target back to the pool.
	 */
	void ReleaseRenderTarget(UTextureRenderTarget2D* RenderTarget);

	/**
	 * Get the total memory used by the render target pool (in MB).
	 */
	UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Capture|Manager")
	float GetPoolMemoryUsageMB() const;

	// ========================================================================
	// Query
	// ========================================================================

	/**
	 * Get the nearest capture surface of a given mode to a world location.
	 */
	UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Capture|Manager")
	ABP_PlanarCaptureActor* GetNearestSurfaceOfMode(
		EPlanarCaptureMode Mode, FVector WorldLocation, float MaxDistance = 0.0f) const;

	/**
	 * Force all surfaces to a specific quality tier (e.g., for cutscenes).
	 */
	UFUNCTION(BlueprintCallable, Category = "Capture|Manager")
	void ForceAllSurfacesToTier(EPlanarCaptureQualityTier Tier);

	/**
	 * Release the force-tier override and resume normal scoring.
	 */
	UFUNCTION(BlueprintCallable, Category = "Capture|Manager")
	void ReleaseForceTier();

	// ========================================================================
	// Event Dispatchers
	// ========================================================================

	UPROPERTY(BlueprintAssignable, Category = "Capture|Manager|Events")
	FOnSurfaceRegistered OnSurfaceRegistered;

	UPROPERTY(BlueprintAssignable, Category = "Capture|Manager|Events")
	FOnSurfaceUnregistered OnSurfaceUnregistered;

	UPROPERTY(BlueprintAssignable, Category = "Capture|Manager|Events")
	FOnGlobalQualityCapChanged OnGlobalQualityCapChanged;

protected:
	// ========================================================================
	// Internal State
	// ========================================================================

	/** All registered capture surface actors. */
	UPROPERTY()
	TArray<TWeakObjectPtr<ABP_PlanarCaptureActor>> RegisteredSurfaces;

	/** Render target pool. */
	TArray<FPlanarCaptureRenderTargetEntry> RenderTargetPool;

	/** Time accumulator for full re-evaluation interval. */
	float TimeSinceLastEvaluation = 0.0f;

	/** Force-tier override — if set, all surfaces use this tier. */
	TOptional<EPlanarCaptureQualityTier> ForceTierOverride;

	/** Count of surfaces at each tier (tracked for budget enforcement). */
	TMap<EPlanarCaptureQualityTier, int32> TierAssignmentCounts;

	// ========================================================================
	// Internal Methods
	// ========================================================================

	/** Evaluate all registered surfaces and assign quality tiers. */
	void EvaluateAllSurfaces();

	/**
	 * Score a single surface and determine its quality tier within budget constraints.
	 * @return The assigned tier.
	 */
	EPlanarCaptureQualityTier ScoreAndAssignTier(UBPC_PlanarCapture* Capture);

	/** Enforce budget limits — demote lower-priority surfaces if budget exceeded. */
	void EnforceBudgetLimits();

	/** Create a new render target of the given size. */
	UTextureRenderTarget2D* CreateRenderTarget(int32 Size);

	/** Get or create a render target for a given size (first checks pool). */
	UTextureRenderTarget2D* GetOrCreateRenderTarget(int32 Size);
};
