// Copyright Ngonart OU. All Rights Reserved.
// UE5 Modular Game Framework — BP_PlanarCaptureActor implementation

#include "Capture/BP_PlanarCaptureActor.h"
#include "Capture/BPC_PlanarCapture.h"
#include "Capture/SS_PlanarCaptureManager.h"
#include "Components/StaticMeshComponent.h"
#include "Components/BoxComponent.h"
#include "Materials/MaterialInstanceDynamic.h"
#include "Materials/MaterialParameterCollection.h"
#include "Engine/World.h"
#include "Net/UnrealNetwork.h"

ABP_PlanarCaptureActor::ABP_PlanarCaptureActor()
{
	PrimaryActorTick.bCanEverTick = false;

	// Create root component
	USceneComponent* Root = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
	SetRootComponent(Root);

	// Surface mesh
	SurfaceMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SurfaceMesh"));
	SurfaceMesh->SetupAttachment(Root);
	SurfaceMesh->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
	SurfaceMesh->SetCollisionResponseToAllChannels(ECR_Ignore);
	SurfaceMesh->SetCollisionResponseToChannel(ECC_Visibility, ECR_Block);

	// Proximity trigger for quality scoring
	ProximityTrigger = CreateDefaultSubobject<UBoxComponent>(TEXT("ProximityTrigger"));
	ProximityTrigger->SetupAttachment(Root);
	ProximityTrigger->SetBoxExtent(FVector(500.0f, 500.0f, 500.0f));
	ProximityTrigger->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
	ProximityTrigger->SetCollisionResponseToAllChannels(ECR_Ignore);
	ProximityTrigger->SetCollisionResponseToChannel(ECC_Pawn, ECR_Overlap);

	// Capture component
	CaptureComponent = CreateDefaultSubobject<UBPC_PlanarCapture>(TEXT("CaptureComponent"));

	// Replication
	bReplicates = true;
	bAlwaysRelevant = true;
}

void ABP_PlanarCaptureActor::BeginPlay()
{
	Super::BeginPlay();

	// Bind overlap events
	if (ProximityTrigger)
	{
		ProximityTrigger->OnComponentBeginOverlap.AddDynamic(this, &ABP_PlanarCaptureActor::OnProximityBeginOverlap);
		ProximityTrigger->OnComponentEndOverlap.AddDynamic(this, &ABP_PlanarCaptureActor::OnProximityEndOverlap);
	}

	CreateMaterialInstance();
	RegisterWithManager();

	if (bStartEnabled)
	{
		EnableSurface();
	}
}

void ABP_PlanarCaptureActor::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
	// Unregister from manager
	if (UWorld* World = GetWorld())
	{
		if (USS_PlanarCaptureManager* Manager = World->GetSubsystem<USS_PlanarCaptureManager>())
		{
			Manager->UnregisterSurface(this);
		}
	}

	Super::EndPlay(EndPlayReason);
}

// ========================================================================
// Public API
// ========================================================================

void ABP_PlanarCaptureActor::EnableSurface()
{
	if (bIsActive)
	{
		return;
	}

	bIsActive = true;
	bRepIsActive = true;

	if (CaptureComponent)
	{
		CaptureComponent->InitializeCapture();
	}
}

void ABP_PlanarCaptureActor::DisableSurface()
{
	if (!bIsActive)
	{
		return;
	}

	bIsActive = false;
	bRepIsActive = false;

	if (CaptureComponent)
	{
		CaptureComponent->ShutdownCapture();
	}
}

void ABP_PlanarCaptureActor::SetCaptureMode(EPlanarCaptureMode NewMode)
{
	if (CaptureComponent)
	{
		const bool WasCapturing = CaptureComponent->bIsCapturing;
		if (WasCapturing)
		{
			CaptureComponent->ShutdownCapture();
		}

		CaptureComponent->CaptureMode = NewMode;

		if (WasCapturing)
		{
			CaptureComponent->InitializeCapture();
		}

		OnModeChanged.Broadcast(NewMode);
	}
}

void ABP_PlanarCaptureActor::SetSurfaceMaterial(UMaterialInterface* NewMaterial)
{
	if (SurfaceMesh && NewMaterial)
	{
		SurfaceMaterialInstance = SurfaceMesh->CreateDynamicMaterialInstance(0, NewMaterial);
	}
}

void ABP_PlanarCaptureActor::SetSurfaceMPCParameter(FName ParameterName, float Value)
{
	UMaterialInstanceDynamic* MID = SurfaceMaterialInstance;
	if (!MID)
	{
		return;
	}

	MID->SetScalarParameterValue(ParameterName, Value);
}

void ABP_PlanarCaptureActor::DestroySurface()
{
	if (!bDestructible)
	{
		return;
	}

	DisableSurface();

	OnSurfaceDestroyed.Broadcast(this);

	// Blueprint child handles visual destruction (particles, sound via SS_AudioManager, etc.)
}

// ========================================================================
// Overlap Events
// ========================================================================

void ABP_PlanarCaptureActor::OnProximityBeginOverlap(UPrimitiveComponent* OverlappedComponent,
	AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex,
	bool bFromSweep, const FHitResult& SweepResult)
{
	// Player entered proximity — notify capture component for quality scoring
	if (CaptureComponent && OtherActor && OtherActor->ActorHasTag(FName("Player")))
	{
		CaptureComponent->SetScriptedPriority(0.3f); // Slight priority boost when player is near
	}
}

void ABP_PlanarCaptureActor::OnProximityEndOverlap(UPrimitiveComponent* OverlappedComponent,
	AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
	if (CaptureComponent && OtherActor && OtherActor->ActorHasTag(FName("Player")))
	{
		CaptureComponent->SetScriptedPriority(0.0f); // Reset priority
	}
}

// ========================================================================
// Replication
// ========================================================================

void ABP_PlanarCaptureActor::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);

	DOREPLIFETIME(ABP_PlanarCaptureActor, bRepIsActive);
}

void ABP_PlanarCaptureActor::OnRep_IsActive()
{
	if (bRepIsActive && !bIsActive)
	{
		EnableSurface();
	}
	else if (!bRepIsActive && bIsActive)
	{
		DisableSurface();
	}
}

// ========================================================================
// Internal
// ========================================================================

void ABP_PlanarCaptureActor::RegisterWithManager()
{
	UWorld* World = GetWorld();
	if (!World)
	{
		return;
	}

	USS_PlanarCaptureManager* Manager = World->GetSubsystem<USS_PlanarCaptureManager>();
	if (Manager)
	{
		Manager->RegisterSurface(this);
	}
}

void ABP_PlanarCaptureActor::CreateMaterialInstance()
{
	if (SurfaceMesh && SurfaceMesh->GetMaterial(0))
	{
		SurfaceMaterialInstance = SurfaceMesh->CreateDynamicMaterialInstance(0);
	}
}
