// Fill out your copyright notice in the Description page of Project Settings.


#include "SpaceShip.h"

#include "Components/ArrowComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Kismet/GameplayStatics.h"
#include "Kismet/KismetMathLibrary.h"

// Sets default values
ASpaceShip::ASpaceShip()
{
 	// Set this pawn to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;
}

void ASpaceShip::SightCheck()
{
	FHitResult OutHit;
	FCollisionObjectQueryParams ObjectQueryParams;
	ObjectQueryParams.AddObjectTypesToQuery(ECollisionChannel::ECC_GameTraceChannel2);
	FVector LT_Start = SeatComponent->GetComponentLocation();
	FVector LT_End = LT_Start + (SeatComponent->GetForwardVector() * 500000);
	GetWorld()->LineTraceSingleByObjectType(OutHit, LT_Start, LT_End, ObjectQueryParams);
	ALandingZone* LZ = Cast<ALandingZone>(OutHit.GetActor());
	if (!IsValid(LZ))
	{
		Potential_LZ = nullptr;
		return;
	}
	Potential_LZ = LZ;
	LZ->SuggestLandingWidget();
}


// Called when the game starts or when spawned
void ASpaceShip::BeginPlay()
{
	Super::BeginPlay();

	BikeParentComp = Cast<USpringArmComponent>(GetComponentByClass(USpringArmComponent::StaticClass()));
	
	PlayersCharacter = GetWorld()->GetFirstPlayerController()->GetCharacter();
	PlayersController = PlayersCharacter->GetController();
	TArray<UActorComponent*> SeatComps = GetComponentsByTag(UArrowComponent::StaticClass(), FName("Seat"));
	SeatComponent = Cast<UArrowComponent>(SeatComps[0]);
}

void ASpaceShip::BikeSwayBasedOnAcc(float DeltaTime)
{
	float LeanSpeed = 90.f;
	float ForwardLeanIncrement = LeanSpeed * DeltaTime * MovementVec.Y;
	float RightLeanIncrement = LeanSpeed * DeltaTime * MovementVec.X;

	FRotator BikeRelativeRot = BikeParentComp->GetRelativeRotation();
	float BikePitch = BikeRelativeRot.Pitch;
	float BikeRoll = BikeRelativeRot.Roll;
	BikeRelativeRot.Pitch = FMath::Clamp(BikePitch + ForwardLeanIncrement, -5.f, 5.f);
	BikeRelativeRot.Roll = FMath::Clamp(BikeRoll + RightLeanIncrement, -30.f, 30.f);

	if (MovementVec.Y == 0) BikeRelativeRot.Pitch = BikePitch > 0 ? FMath::Clamp(BikePitch - ((LeanSpeed / 2.f) * DeltaTime), 0.f, 99.f) : FMath::Clamp(BikePitch + ((LeanSpeed / 2.f) * DeltaTime), -99, 0.f);
	if (MovementVec.X == 0) BikeRelativeRot.Roll = BikeRoll > 0 ? FMath::Clamp(BikeRoll - ((LeanSpeed / 2.f) * DeltaTime), 0.f, 99.f) : FMath::Clamp(BikeRoll + ((LeanSpeed / 2.f) * DeltaTime), -99, 0.f);
	
	BikeParentComp->SetRelativeRotation(BikeRelativeRot);
}

// Called every frame
void ASpaceShip::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	PlayersCharacter->SetActorLocation(SeatComponent->GetComponentLocation());
	PlayersController->SetControlRotation(GetActorRotation());
	BikeSwayBasedOnAcc(DeltaTime);
		
	SightCheck();
}

// Called to bind functionality to input
void ASpaceShip::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

}

void ASpaceShip::PlayerInteracting()
{
	if (IsValid(Potential_LZ)) Potential_LZ->Land();	
}


void ASpaceShip::MoveShip(FVector2D MovementVector)
{
	MovementVec = MovementVector;
	GetWorld()->GetTimerManager().SetTimer(BikeLeanResetTimer, this, &ASpaceShip::ResetBikeLean, 0.2f);
	// Get ships direction vectors, and ignore their pitch
	FVector ForwardVector = GetActorForwardVector();
	ForwardVector.Z = 0;
	FVector RightVector = GetActorRightVector();
	RightVector.Y += RightVector.Z;
	RightVector.Z = 0;
	AddMovementInput(ForwardVector, MovementVector.Y, true);
	AddMovementInput(RightVector, MovementVector.X, true);
}

void ASpaceShip::RotateShip(FVector2D LookAxisVector)
{
	FRotator shipRotator = GetActorRotation();
	shipRotator.Yaw += LookAxisVector.X;
	shipRotator.Pitch -= LookAxisVector.Y;
	shipRotator.Pitch = shipRotator.Pitch < -30 ? -30 : shipRotator.Pitch;
	shipRotator.Pitch = shipRotator.Pitch > 30 ? 30 : shipRotator.Pitch;
	SetActorRotation(shipRotator);
}

