#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "HyperTwistXR/HyperTwistXrRuntimeLibrary.h"
#include "HyperTwistXrTrainingPawn.generated.h"

class UCameraComponent;
class UMotionControllerComponent;
class USceneComponent;

UCLASS(BlueprintType, Blueprintable)
class UNREALHYPERTWIST_API AHyperTwistXrTrainingPawn : public APawn
{
	GENERATED_BODY()

public:
	AHyperTwistXrTrainingPawn();

	virtual void BeginPlay() override;
	virtual void Tick(float DeltaSeconds) override;
	virtual void SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) override;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|XR|Preferences")
	FHyperTwistXrPreferenceProfile ActivePreferenceProfile;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|XR|Bindings")
	FHyperTwistXrControllerBindingProfile ActiveControllerBindingProfile;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|XR|Runtime")
	bool bAutoResetOrientationOnBeginPlay = true;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|XR|Runtime")
	TObjectPtr<USceneComponent> SceneRoot = nullptr;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|XR|Runtime")
	TObjectPtr<USceneComponent> VROrigin = nullptr;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|XR|Runtime")
	TObjectPtr<UCameraComponent> CameraComponent = nullptr;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|XR|Runtime")
	TObjectPtr<UMotionControllerComponent> LeftController = nullptr;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|XR|Runtime")
	TObjectPtr<UMotionControllerComponent> RightController = nullptr;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|XR|Runtime")
	TObjectPtr<USceneComponent> LeftPointerAnchor = nullptr;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|XR|Runtime")
	TObjectPtr<USceneComponent> RightPointerAnchor = nullptr;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|XR|Runtime")
	bool bHeadMountedDisplayConnected = false;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|XR|Runtime")
	bool bHeadMountedDisplayEnabled = false;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|XR|Runtime")
	float LeftGripValue = 0.0f;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|XR|Runtime")
	float RightGripValue = 0.0f;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|XR|Runtime")
	float LeftTriggerValue = 0.0f;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|XR|Runtime")
	float RightTriggerValue = 0.0f;

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|XR|Preferences")
	void ApplyPreferenceProfile(const FHyperTwistXrPreferenceProfile& PreferenceProfile);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|XR|Preferences")
	void SetDominantHand(EHyperTwistXrDominantHand DominantHand);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|XR|Preferences")
	void SetPostureMode(EHyperTwistXrPostureMode PostureMode);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|XR|Preferences")
	void SetSnapTurnEnabled(bool bEnabled);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|XR|Preferences")
	void ResetXrOrigin();

	UFUNCTION(BlueprintPure, Category = "HyperTwist|XR|Runtime")
	FHyperTwistXrRuntimeOwnershipSurface GetBoundedRuntimeOwnershipSurface() const;

	UFUNCTION(BlueprintPure, Category = "HyperTwist|XR|Runtime")
	FString BuildRuntimeStatusLine() const;

	UFUNCTION(BlueprintPure, Category = "HyperTwist|XR|Runtime")
	bool HasObservedHeadMountedDisplaySession() const;

	UFUNCTION(BlueprintPure, Category = "HyperTwist|XR|Runtime")
	float GetControllerInputObservationMagnitude() const;

	UFUNCTION(BlueprintPure, Category = "HyperTwist|XR|Runtime")
	bool HasObservedControllerInputActivity() const;

protected:
	void ApplyPostureOffset();
	void ApplyPointerAnchors();
	void ApplyDesktopFallbackRotation();
	void RefreshHeadMountedDisplayState();
	void UpdateSmoothLocomotion(float DeltaSeconds);
	void UpdateVerticalAdjustment(float DeltaSeconds);
	void UpdateTurn(float DeltaSeconds);
	void UpdateDesktopFallbackPitch(float DeltaSeconds);

	void HandleMoveForward(float Value);
	void HandleMoveRight(float Value);
	void HandleVerticalAdjustAxis(float Value);
	void HandleTurnAxis(float Value);
	void HandleLookPitchAxis(float Value);
	void HandleLeftGripAxis(float Value);
	void HandleRightGripAxis(float Value);
	void HandleLeftTriggerAxis(float Value);
	void HandleRightTriggerAxis(float Value);
	void HandleToggleSnapTurn();
	void HandleTogglePostureMode();

	float PendingMoveForward = 0.0f;
	float PendingMoveRight = 0.0f;
	float PendingVerticalAdjust = 0.0f;
	float PendingTurnAxis = 0.0f;
	float PendingLookPitchAxis = 0.0f;
	float ManualVerticalAdjustmentUnits = 0.0f;
	float DesktopFallbackPitchDegrees = 0.0f;
	bool bSnapTurnLatchOpen = true;
};
