// (C) MAI 2020. All rights reserved.

#pragma once

#include "Camera/CameraComponent.h"
#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "Actor/BaseMotionController.h"

#include "InverseWorldPawn.generated.h"

USTRUCT()
struct FPlatformControllers
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere)
	TSubclassOf<ABaseMotionController> ControllerRightHand;

	UPROPERTY(EditAnywhere)
	TSubclassOf<ABaseMotionController> ControllerLeftHand;
};

UCLASS()
class AInverseWorldPawn : public APawn
{
	GENERATED_BODY()
public:
	UPROPERTY(VisibleAnywhere)
	USceneComponent* HMDScene;

	UPROPERTY(VisibleAnywhere)
	UCameraComponent* VRCamera;

	UPROPERTY(EditAnywhere)
	FPlatformControllers DefaultControllers;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Controllers")
	ABaseMotionController* RightController;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Controllers")
	ABaseMotionController* LeftController;

	float CurrentScale = 1.0f;

	// Sets default values for this pawn's properties.
	AInverseWorldPawn();

	// Called when the game starts or when spawned.
	virtual void BeginPlay() override;

	// Sets up action bindings that are purely propagated to the controllers with no effect on the pawn.
	virtual void SetupControllerInputs();

	// Called every frame.
	virtual void Tick(float DeltaTime) override;

	// Resets everything to it's default transform.
	void ResetTransform();

protected:

	// The actor that is considered the "center of the world".
	// We take it's transform and move the world around it.
	AActor* PivotActor;

	TArray<AActor*> MovingActors;
	TMap<AActor*, FTransform> MovingActorDefaultTransforms;

	FVector LastLeftControllerLocation;
	FVector LastRightControllerLocation;

	FRotator LastLeftControllerRotation;
	FRotator LastRightControllerRotation;

	float LastWorldToMeters = 100.f;

	float TranslationSpeed = 2.0f;

	float MaxScale = 10;

	float MinScale = 0.2;

	void FixActorLocationAccordingToScaleChange(AActor* InOutActor, const float InScaleChangeRatio);

	void TransformActor(AActor* InOutActor, const FTransform& InTransformChange);

	void CompensateActorRotationAroundPivot(AActor* InOutActor, const FTransform& InTransformChange);

	void ScaleWorld(FTransform& InOutTransformChange);

	virtual void HandleControllerTick(float DeltaTime);

	FTransform CalculateTransformChange();

	void SaveControllerTransforms();

	void SaveWorldToMeters();
};
