// Copyright Ngonart OU. All Rights Reserved.
// UE5 Modular Game Framework — PlanarCaptureCameraUtils
// Static math library for mirror reflection, portal relative transform,
// oblique projection, screen coverage, and visibility computations.
// All functions are BlueprintCallable and use UE5's FMatrix/FVector/FPlane types.

#pragma once

#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "PlanarCaptureCameraUtils.generated.h"

/**
 * Static math library for planar capture camera transforms.
 *
 * Mirror: reflect the viewer camera across the mirror plane.
 * Portal: compute the relative transform from source surface to target surface.
 * All math happens in C++ for performance — Blueprint calls these as pure functions.
 */
UCLASS()
class PG_FRAMEWORK_API UPlanarCaptureCameraUtils : public UBlueprintFunctionLibrary
{
	GENERATED_BODY()

public:
	// ========================================================================
	// Mirror Reflection Math
	// ========================================================================

	/**
	 * Compute the mirrored camera transform for a planar mirror.
	 * Reflects the viewer's camera position and rotation across the mirror plane.
	 *
	 * @param ViewerCameraTransform  World transform of the viewer's camera.
	 * @param MirrorPlaneTransform   World transform of the mirror surface (XY plane, Z = normal).
	 * @return                       The world transform for the SceneCapture camera.
	 */
	UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Capture|CameraUtils")
	static FTransform ComputeMirroredTransform(
		const FTransform& ViewerCameraTransform,
		const FTransform& MirrorPlaneTransform);

	// ========================================================================
	// Portal Relative Math
	// ========================================================================

	/**
	 * Compute the capture camera transform for a portal.
	 * The viewer's position relative to the source surface is mapped to the
	 * target surface's coordinate space.
	 *
	 * @param ViewerCameraTransform  World transform of the viewer's camera.
	 * @param SourceSurfaceTransform World transform of the portal entry surface.
	 * @param TargetSurfaceTransform World transform of the portal exit surface.
	 * @return                       The world transform for the SceneCapture camera.
	 */
	UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Capture|CameraUtils")
	static FTransform ComputePortalTransform(
		const FTransform& ViewerCameraTransform,
		const FTransform& SourceSurfaceTransform,
		const FTransform& TargetSurfaceTransform);

	// ========================================================================
	// Oblique Near-Plane Projection
	// ========================================================================

	/**
	 * Compute an oblique near-clip-plane projection matrix.
	 * Used to prevent geometry behind the portal/mirror surface from clipping
	 * into the capture view.
	 *
	 * @param FOV               Horizontal field of view in degrees.
	 * @param AspectRatio       Width / Height.
	 * @param NearPlane         Near clip distance.
	 * @param FarPlane          Far clip distance.
	 * @param ClipPlane         World-space plane to clip against.
	 * @param SurfaceTransform  Transform of the surface (for converting clip plane to view space).
	 * @return                  The oblique projection matrix.
	 */
	UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Capture|CameraUtils")
	static FMatrix ComputeObliqueProjectionMatrix(
		float FOV,
		float AspectRatio,
		float NearPlane,
		float FarPlane,
		const FPlane& ClipPlane,
		const FTransform& SurfaceTransform);

	// ========================================================================
	// Screen Coverage & Visibility
	// ========================================================================

	/**
	 * Estimate how much of the screen a capture surface occupies (0.0 to 1.0).
	 * Uses the surface's bounding box corners projected to screen-space.
	 *
	 * @param SurfaceBounds     Bounding box of the surface mesh in world space.
	 * @param ViewerTransform   World transform of the viewer's camera.
	 * @param ViewerFOV         Horizontal FOV of the viewer.
	 * @param ScreenWidth       Viewport width in pixels.
	 * @param ScreenHeight      Viewport height in pixels.
	 * @return                  Estimated screen coverage ratio (0.0 to 1.0).
	 */
	UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Capture|CameraUtils")
	static float ComputeScreenCoverage(
		const FBox& SurfaceBounds,
		const FTransform& ViewerTransform,
		float ViewerFOV,
		int32 ScreenWidth,
		int32 ScreenHeight);

	/**
	 * Check whether the surface is visible to the viewer's frustum.
	 *
	 * @param SurfaceBounds       Bounding box of the surface mesh in world space.
	 * @param ViewerTransform     World transform of the viewer's camera.
	 * @param ViewerFOV           Horizontal FOV.
	 * @param ViewerAspectRatio   Width / Height.
	 * @param ViewerNearPlane     Near clip distance.
	 * @param ViewerFarPlane      Far clip distance.
	 * @return                    True if any part of the surface is within the frustum.
	 */
	UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Capture|CameraUtils")
	static bool IsSurfaceVisibleToViewer(
		const FBox& SurfaceBounds,
		const FTransform& ViewerTransform,
		float ViewerFOV,
		float ViewerAspectRatio,
		float ViewerNearPlane,
		float ViewerFarPlane);

	// ========================================================================
	// Quality Scoring
	// ========================================================================

	/**
	 * Compute a composite priority score for a capture surface.
	 * Higher score = higher quality tier assignment.
	 * Formula: (ScreenCoverage * 0.5) + (FacingAngle * 0.3) + (DistanceFactor * 0.1) + (ScriptedPriority * 0.1)
	 *
	 * @param ScreenCoverage    How much screen real estate the surface occupies.
	 * @param FacingAngle       Dot product of viewer forward to surface normal.
	 * @param DistanceToViewer  Distance in world units.
	 * @param MaxDistance       Distance at which score drops to zero.
	 * @param ScriptedPriority  Priority override from gameplay systems (0.0 to 1.0).
	 * @return                  Composite score (0.0 to 1.0).
	 */
	UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Capture|CameraUtils")
	static float ComputeCompositeScore(
		float ScreenCoverage,
		float FacingAngle,
		float DistanceToViewer,
		float MaxDistance,
		float ScriptedPriority);
};
