// Copyright Ngonart OU. All Rights Reserved.
// UE5 Modular Game Framework — BPC_PlanarCapture (136)
// The heart of the Planar Capture System. Attached to any actor that needs
// a scene capture — mirrors, portals, monitors, horror surfaces.
//
// Manages USceneCaptureComponent2D lifetime, render target pool allocation,
// camera transform computation per mode, oblique clip plane injection,
// show/hide actor lists, quality tier application, frame ring buffer,
// and MPC parameter pushes.

#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "Capture/PlanarCaptureCommon.h"
#include "BPC_PlanarCapture.generated.h"

// Forward declarations
class USceneCaptureComponent2D;
class UTextureRenderTarget2D;
class UMaterialInstanceDynamic;
class UMaterialParameterCollection;
class USS_PlanarCaptureManager;
class ABP_PlanarCaptureActor;

// ============================================================================
// Delegates
// ============================================================================

DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnCaptureQualityChanged, EPlanarCaptureQualityTier, OldTier, EPlanarCaptureQualityTier, NewTier);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnCaptureInitialized, EPlanarCaptureInitResult, Result);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnCaptureRendered);

/**
 * BPC_PlanarCapture — Core capture component for mirrors, portals, monitors, etc.
 *
 * Owns the USceneCaptureComponent2D lifecycle. All camera math, render target
 * management, and per-frame capture decisions happen here in C++ for performance.
 * Designer configuration flows through Blueprint children.
 *
 * Multiplayer: Capture is always local-only. Each client renders their own view.
 * No replication needed. This component only exists on clients.
 */
UCLASS(Blueprintable, ClassGroup = (Framework), meta = (BlueprintSpawnableComponent))
class PG_FRAMEWORK_API UBPC_PlanarCapture : public UActorComponent
{
	GENERATED_BODY()

public:
	UBPC_PlanarCapture();

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

	virtual void BeginPlay() override;
	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
	virtual void TickComponent(float DeltaTime, ELevelTick TickType,
		FActorComponentTickFunction* ThisTickFunction) override;

	// ========================================================================
	// Configuration — Set in Blueprint Defaults
	// ========================================================================

	/** What kind of surface this capture represents. */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Capture|Config")
	EPlanarCaptureMode CaptureMode = EPlanarCaptureMode::Mirror;

	/** Quality profiles per tier (0=Low, 1=Medium, 2=High, 3=Hero). Index maps to EPlanarCaptureQualityTier. */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Capture|Config")
	TArray<FPlanarCaptureQualityProfile> QualityProfiles;

	/** FOV for the capture camera. */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Capture|Config")
	float CaptureFOV = 90.0f;

	/** Maximum view distance for the capture (0 = unlimited). */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Capture|Config")
	float MaxViewDistance = 5000.0f;

	// ========================================================================
	// Portal Configuration
	// ========================================================================

	/** For Portal mode: the linked target surface actor. */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Capture|Portal")
	TSoftObjectPtr<ABP_PlanarCaptureActor> LinkedTargetSurface;

	// ========================================================================
	// Monitor Configuration
	// ========================================================================

	/** For Monitor mode: a fixed camera actor to capture from. */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Capture|Monitor")
	TSoftObjectPtr<AActor> FixedCameraActor;

	// ========================================================================
	// Actor Lists
	// ========================================================================

	/** Actors to show exclusively in the capture (empty = show all). */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Capture|ActorLists")
	TArray<FPlanarCaptureActorListEntry> ShowOnlyActors;

	/** Actors to hide from the capture. */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Capture|ActorLists")
	TArray<FPlanarCaptureActorListEntry> HiddenActors;

	// ========================================================================
	// Horror Configuration
	// ========================================================================

	/** Actor to swap into the ShowOnly list during wrong-reflection events. */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Capture|Horror")
	TSoftObjectPtr<AActor> WrongReflectionActor;

	/** Mesh component of the surface plane (for clip plane calculation). */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Capture|Config")
	TSoftObjectPtr<UStaticMeshComponent> SurfaceMeshComponent;

	// ========================================================================
	// Runtime State (Read-Only)
	// ========================================================================

	/** Current assigned quality tier (set by SS_PlanarCaptureManager). */
	UPROPERTY(BlueprintReadOnly, Category = "Capture|Runtime")
	EPlanarCaptureQualityTier CurrentQualityTier = EPlanarCaptureQualityTier::Off;

	/** Is this capture currently active (capturing frames)? */
	UPROPERTY(BlueprintReadOnly, Category = "Capture|Runtime")
	bool bIsCapturing = false;

	/** The render target this capture writes to. */
	UPROPERTY(BlueprintReadOnly, Category = "Capture|Runtime")
	TObjectPtr<UTextureRenderTarget2D> CaptureRenderTarget;

	// ========================================================================
	// Public API — BlueprintCallable
	// ========================================================================

	/**
	 * Initialize the capture component. Allocates render target, creates and
	 * configures the USceneCaptureComponent2D. Called by the owning actor on BeginPlay.
	 */
	UFUNCTION(BlueprintCallable, Category = "Capture")
	EPlanarCaptureInitResult InitializeCapture();

	/**
	 * Shut down the capture, release render target back to pool, destroy SceneCaptureComponent2D.
	 */
	UFUNCTION(BlueprintCallable, Category = "Capture")
	void ShutdownCapture();

	/**
	 * Apply a quality tier profile immediately. Called by SS_PlanarCaptureManager.
	 */
	UFUNCTION(BlueprintCallable, Category = "Capture")
	void ApplyQualityTier(EPlanarCaptureQualityTier Tier);

	/**
	 * Trigger a single capture frame immediately (bypasses tick interval).
	 */
	UFUNCTION(BlueprintCallable, Category = "Capture")
	void CaptureNow();

	/**
	 * Swap the ShowOnly actor list to the wrong-reflection actor (horror mode).
	 * Original list is preserved and restored on DeactivateHorrorReflection().
	 */
	UFUNCTION(BlueprintCallable, Category = "Capture|Horror")
	void ActivateHorrorReflection();

	/**
	 * Restore the original ShowOnly actor list after a horror event.
	 */
	UFUNCTION(BlueprintCallable, Category = "Capture|Horror")
	void DeactivateHorrorReflection();

	/**
	 * Push a frame from the ring buffer into the render target for delayed reflection (horror lag).
	 */
	UFUNCTION(BlueprintCallable, Category = "Capture|Horror")
	void PushDelayedFrame();

	/**
	 * Set a scripted priority override (0.0 to 1.0). Higher values force higher quality tier.
	 * Example: a scare event elevates a specific mirror to Hero tier.
	 */
	UFUNCTION(BlueprintCallable, Category = "Capture")
	void SetScriptedPriority(float Priority);

	/**
	 * Push all Material Parameter Collection values for this surface.
	 * Called every frame when capturing, or on event trigger for horror params.
	 */
	UFUNCTION(BlueprintCallable, Category = "Capture|Material")
	void PushMPCParameters(UMaterialParameterCollection* MPC);

	// ========================================================================
	// Compute — BlueprintPure
	// ========================================================================

	/** Compute the capture camera transform for the current mode. */
	UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Capture")
	FTransform ComputeCaptureCameraTransform(const FTransform& ViewerCameraTransform) const;

	/** Get the current composite quality score. */
	UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Capture")
	FPlanarCaptureScore GetCurrentScore() const;

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

	UPROPERTY(BlueprintAssignable, Category = "Capture|Events")
	FOnCaptureQualityChanged OnCaptureQualityChanged;

	UPROPERTY(BlueprintAssignable, Category = "Capture|Events")
	FOnCaptureInitialized OnCaptureInitialized;

	UPROPERTY(BlueprintAssignable, Category = "Capture|Events")
	FOnCaptureRendered OnCaptureRendered;

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

	/** The actual UE5 SceneCaptureComponent2D — created at runtime. */
	UPROPERTY()
	TObjectPtr<USceneCaptureComponent2D> SceneCapture;

	/** Cached reference to the manager subsystem. */
	UPROPERTY()
	TObjectPtr<USS_PlanarCaptureManager> CachedManager;

	/** Cached reference to the owning actor. */
	UPROPERTY()
	TObjectPtr<ABP_PlanarCaptureActor> CachedOwningActor;

	/** Time accumulator for capture interval throttling. */
	float TimeSinceLastCapture = 0.0f;

	/** Current quality profile (cached from QualityProfiles[Tier]). */
	FPlanarCaptureQualityProfile ActiveProfile;

	/** Scripted priority override (0.0 to 1.0). */
	float ScriptedPriorityOverride = 0.0f;

	/** Ring buffer of render targets for delayed reflection (horror mode). */
	UPROPERTY()
	TArray<TObjectPtr<UTextureRenderTarget2D>> FrameRingBuffer;

	/** Current write index into the frame ring buffer. */
	int32 RingBufferWriteIndex = 0;

	/** Saved ShowOnly list before horror swap. */
	TArray<TSoftObjectPtr<AActor>> SavedShowOnlyActors;

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

	/** Create and configure the USceneCaptureComponent2D. */
	void CreateSceneCaptureComponent();

	/** Apply show flags from the active quality profile to the SceneCapture. */
	void ApplyShowFlags();

	/** Update the ShowOnly and Hidden actor lists on the SceneCapture. */
	void UpdateActorLists();

	/** Resolve soft references on initialization. */
	void ResolveSoftReferences();

	/** Compute the surface plane in world space for clip plane and mirror math. */
	FPlane GetSurfacePlane() const;
};
