#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "InteractionComponent.generated.h"

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnFocusedInteractableChanged, AActor*, NewFocused);

UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class NAKEDDESIRE_API UInteractionComponent : public UActorComponent
{
	GENERATED_BODY()

public:
	UInteractionComponent();
	
	virtual void BeginPlay() override;

	// Call from interact input — sends server RPC if not authority
	void Interact();

	UFUNCTION(BlueprintPure)
	AActor* GetFocusedInteractable() const { return FocusedInteractable.Get(); }

	// Broadcasts whenever the focused (interactable) actor changes; nullptr = no target
	UPROPERTY(BlueprintAssignable)
	FOnFocusedInteractableChanged OnFocusedInteractableChanged;

protected:

	// Actors within this radius receive a proximity outline
	UPROPERTY(EditDefaultsOnly, Category="Interaction")
	float ProximityRadius = 350.f;

	// Player must be within this distance to focus an interactable (must be <= ProximityRadius)
	UPROPERTY(EditDefaultsOnly, Category="Interaction")
	float InteractionDistance = 150.f;

	// Minimum dot product between look direction and direction to target.
	// cos(20°) ≈ 0.94 — lower values allow a wider look cone.
	UPROPERTY(EditDefaultsOnly, Category="Interaction")
	float LookDotThreshold = 0.9f;

	// Draw the eye→target line-of-sight trace each check (green = clear, red = blocked).
	UPROPERTY(EditDefaultsOnly, Category="Interaction|Debug")
	bool bDrawDebugLineOfSight = false;

private:
	FTimerHandle InteractionTimerHandle;

	void UpdateInteraction();

	TSet<TWeakObjectPtr<AActor>> NearbyInteractables;
	TWeakObjectPtr<AActor> FocusedInteractable;

	// Physics scan → update NearbyInteractables set → manage proximity outlines
	void UpdateNearbyInteractables();

	// Among nearby actors, find the one best matching look + distance conditions
	void UpdateFocusedInteractable();

	bool GetOwnerViewPoint(FVector& OutLocation, FRotator& OutRotation) const;

	// Traces from the pawn's eye position (NOT the camera) to the target.
	// Returns true only if nothing blocks the line — prevents exploiting the
	// third-person camera to interact through walls by looking over them.
	bool HasLineOfSightFromPawn(AActor* Target) const;
};