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


#include "BountyDirector.h"

#include "Blueprint/UserWidget.h"
#include "Components/ArrowComponent.h"

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

}

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

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

	PlayerChar = Cast<AEndlessVendettaCharacter>(GetWorld()->GetFirstPlayerController()->GetCharacter());
	if (!IsValid(PlayerChar)) UE_LOG(LogTemp, Fatal, TEXT("Players Character isn't being loaded in BeginPlay() in BountyDirector"));

	// Setup a component for bounties to attach to on the player
	for (UActorComponent* ActorComp : PlayerChar->GetComponentsByTag(UArrowComponent::StaticClass(), FName("Bounty")))
	{
		BountyAttachmentPoint = Cast<UArrowComponent>(ActorComp);
		if (!IsValid(BountyAttachmentPoint)) UE_LOG(LogTemp, Fatal, TEXT("There's no Bounty Attachment UArrowComponent on Players Char "));
		break;
	}
	
	SpawnBountyAndItsSideBounties();
}

void ABountyDirector::SpawnBountyAndItsSideBounties()
{
	UE_LOG(LogTemp, Warning, TEXT("Spawning Bounty..."));
	
	if (BountyClassArray.IsEmpty()) return;
 	if (!IsValid(BountyClassArray[CurrentBountyIndex])) UE_LOG(LogTemp, Fatal, TEXT("Missing Bounty at Index: %d"), CurrentBountyIndex);
	
	// Spawn Main Bounty which the current bounty index is pointing to
	FActorSpawnParameters SpawnParams;
	SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
	
	AActor* BountyActor = GetWorld()->SpawnActor<AActor>(BountyClassArray[CurrentBountyIndex], PlayerChar->GetActorLocation(), PlayerChar->GetActorRotation(), SpawnParams);
	const FAttachmentTransformRules AttachmentTransformRules(EAttachmentRule::SnapToTarget, true);
	BountyActor->AttachToComponent(BountyAttachmentPoint, AttachmentTransformRules);

	ActiveBounty = Cast<AMainBountyClass>(BountyActor);
	if (!IsValid(ActiveBounty)) UE_LOG(LogTemp, Fatal, TEXT("Failed to Cast to Bounty class"));

	// WHEN MARCEL STOPS PLAYING WITH THE CHARACTER, ADD THIS BOUNTY TO PLAYERS ARRAY OF ACTIVE BOUNTIES!!!!!
	ActiveBounty->CompletedFirstCheckpoint.AddDynamic(this, &ABountyDirector::DestroyActiveSideBounties);
	ActiveSideBounties.Reset();
	for (TSubclassOf<ASideBountyClass> SideBountyClass : ActiveBounty->GetSideBountiesToSpawn())
	{
		if (!IsValid(SideBountyClass)) continue;
		AActor* SideBountyActor = GetWorld()->SpawnActor<AActor>(SideBountyClass, PlayerChar->GetActorLocation(), PlayerChar->GetActorRotation(), SpawnParams);
		SideBountyActor->AttachToComponent(BountyAttachmentPoint, AttachmentTransformRules);
		ASideBountyClass* SideBounty = Cast<ASideBountyClass>(SideBountyActor);
		if (!IsValid(SideBounty)) UE_LOG(LogTemp, Fatal, TEXT("A SideBounty for %s has been set to a wrong type"), *ActiveBounty->GetBountyTitle());
		int i = ActiveSideBounties.Add(SideBounty);
		ActiveSideBounties[i]->CompletedSideBounty.AddDynamic(this, &ABountyDirector::EarnFavours);
		// ONCE AGAIN WHEN MARCEL STOPS PLAYING WITH THE CHARACTER, ADD THIS SIDE BOUNTY TO PLAYERS ARRAY OF ACTIVE BOUNTIES!!!!!
	}
}

void ABountyDirector::UpdateBountyProgression()
{
	if (!IsValid(ActiveBounty)) return;

	if (ActiveBounty->IsCompleted()) FinishActiveBounty();
}

void ABountyDirector::FinishActiveBounty()
{
	ActiveBounty->CollectRewards();

	// Destroy old Bounties
	ActiveBounty->Destroy();
	DestroyActiveSideBounties();

	// Increment Main and Side Bounty Indexes
	CurrentBountyIndex++;

	// Game Completion Check
	if (CurrentBountyIndex >= BountyClassArray.Num())
	{
		UE_LOG(LogTemp, Warning, TEXT("Finished all bounties currently available in the game :)"));
		ActiveBounty = nullptr;
		return;
	}

	SpawnBountyAndItsSideBounties();
}

void ABountyDirector::DestroyActiveSideBounties()
{
	for (ASideBountyClass* SideBounty : ActiveSideBounties)
	{
		if (!IsValid(SideBounty)) continue;

		// WHEN MARCEL STOPS PLAYING WITH PLAYERS CHARACTER, REMOVE THIS SIDE BOUNTY FROM ACTIVE BOUNTIES

		SideBounty->DestroyCheckpoints();
		SideBounty->Destroy();
	}
}

// ----------- Favour Shop ---------------

void ABountyDirector::EarnFavours(int FavoursEarned)
{
	Favours += FavoursEarned;
}

void ABountyDirector::BuyCustomBountyAlteration_1()
{
	if (!IsValid(ActiveBounty)) return;
	int Cost = ActiveBounty->GetCustomBountyAlteration_1_Cost();
	if (Cost == 0 || Favours < Cost || ActiveBounty->ActivatedCBA_1) return;
	Favours -= Cost;
	PC_Display->UpdateFavourCount(Favours);
	ActiveBounty->ActivatedCBA_1 = true;
	ActiveBounty->ActivateCustomBountyAlteration_1();
}


void ABountyDirector::BuyCustomBountyAlteration_2()
{
	if (!IsValid(ActiveBounty)) return;
	int Cost = ActiveBounty->GetCustomBountyAlteration_2_Cost();
	if (Cost == 0 || Favours < Cost || ActiveBounty->ActivatedCBA_2) return;
	Favours -= Cost;
	PC_Display->UpdateFavourCount(Favours);
	ActiveBounty->ActivatedCBA_2 = true;
	ActiveBounty->ActivateCustomBountyAlteration_2();
}

void ABountyDirector::BuyCustomBountyAlteration_3()
{
	if (!IsValid(ActiveBounty)) return;
	int Cost = ActiveBounty->GetCustomBountyAlteration_3_Cost();
	if (Cost == 0 || Favours < Cost || ActiveBounty->ActivatedCBA_3) return;
	Favours -= Cost;
	PC_Display->UpdateFavourCount(Favours);
	ActiveBounty->ActivatedCBA_3 = true;
	ActiveBounty->ActivateCustomBountyAlteration_3();
}

void ABountyDirector::BuyAmmoDrop()
{
	if (!IsValid(ActiveBounty)) return;
	if (Favours < 1 || ActiveBounty->ActivateAmmoDrops) return;
	Favours--;
	PC_Display->UpdateFavourCount(Favours);
	ActiveBounty->ActivateAmmoDrops = true;
	ActiveBounty->SpawnAmmoDrops();
}

void ABountyDirector::BuyHealthDrop()
{
	if (!IsValid(ActiveBounty)) return;
	if (Favours < 1 || ActiveBounty->ActivatedHealthDrops) return;
	Favours--;
	PC_Display->UpdateFavourCount(Favours);
	ActiveBounty->ActivatedHealthDrops = true;
	ActiveBounty->SpawnHealthDrops();
}

void ABountyDirector::BuyEnemyRadio()
{
	if (!IsValid(ActiveBounty)) return;
	if (Favours < 1 || ActiveBounty->ActivatedRadio) return;
	Favours--;
	PC_Display->UpdateFavourCount(Favours);
	ActiveBounty->ActivatedRadio = true;
	ActiveBounty->ActivateEnemyRadio();
}

void ABountyDirector::BuyFavours()
{
	if (PlayerChar->Money < FavourCost) return;
	PlayerChar->Money -= FavourCost;
	Favours++;
	PC_Display->UpdateFavourCount(Favours);
}

// ----------- PC Display ---------------

void ABountyDirector::Interact()
{
	UpdateBountyProgression();
	FInputModeUIOnly InputMode;
	APlayerController* PlayerController = GetWorld()->GetFirstPlayerController();

	PC_DisplayWidget = CreateWidget<UUserWidget>(GetWorld(), PC_DisplayWidgetClass);
	PC_DisplayWidget->AddToViewport(3);
	
	PlayerController->SetInputMode(InputMode);
	PlayerController->bShowMouseCursor = true;
	PlayerController->bEnableClickEvents = true;
	PlayerController->bEnableMouseOverEvents = true;

	PC_Display = Cast<UPC_Display>(PC_DisplayWidget);
	bool GameOver = !IsValid(ActiveBounty);
	PC_Display->PC_Display_Info.IsGameOver = GameOver;
	PC_Display->LogoutFromBountyDirectorPC.AddDynamic(this, &ABountyDirector::DestroyBountyDirectorPCWidget);

	if (GameOver)
	{
		PC_Display->LoadOS();
		return;
	}

	// Info about main bounty
	PC_Display->PC_Display_Info.MB_Title = GetBountyTitle();
	PC_Display->PC_Display_Info.MB_Desc = GetBountyDescription();
	PC_Display->PC_Display_Info.MB_Reward = GetBountyReward();

	// Info about side bounties
	PC_Display->PC_Display_Info.SB_Title.Reset();
	PC_Display->PC_Display_Info.SB_Icon.Reset();
	PC_Display->PC_Display_Info.SB_Desc.Reset();
	PC_Display->PC_Display_Info.SB_Reward.Reset();
	for (ASideBountyClass* SideBounty : ActiveSideBounties) 
	{
		if (!IsValid(SideBounty) || SideBounty->IsCompleted()) continue;
		PC_Display->PC_Display_Info.SB_Title.Add(SideBounty->GetBountyTitle());
		PC_Display->PC_Display_Info.SB_Icon.Add(SideBounty->GetActiveWaypointIcon());
		PC_Display->PC_Display_Info.SB_Desc.Add(SideBounty->GetBountyDesc());
		PC_Display->PC_Display_Info.SB_Reward.Add(SideBounty->GetRewardInFavours());
	}

	// Info about main bounty alterations
	PC_Display->PC_Display_Info.CustomBountyAlteration_Desc.Reset();
	PC_Display->PC_Display_Info.CustomBountyAlteration_Cost.Reset();

	PC_Display->PC_Display_Info.CustomBountyAlteration_Desc.Add(ActiveBounty->GetCustomBountyAlteration_1_Description());
	PC_Display->PC_Display_Info.CustomBountyAlteration_Desc.Add(ActiveBounty->GetCustomBountyAlteration_2_Description());
	PC_Display->PC_Display_Info.CustomBountyAlteration_Desc.Add(ActiveBounty->GetCustomBountyAlteration_3_Description());

	PC_Display->PC_Display_Info.CustomBountyAlteration_Cost.Add(ActiveBounty->GetCustomBountyAlteration_1_Cost());
	PC_Display->PC_Display_Info.CustomBountyAlteration_Cost.Add(ActiveBounty->GetCustomBountyAlteration_2_Cost());
	PC_Display->PC_Display_Info.CustomBountyAlteration_Cost.Add(ActiveBounty->GetCustomBountyAlteration_3_Cost());

	PC_Display->PC_Display_Info.PlayersFavourAmount = Favours;

	// Button Delegates
	PC_Display->BuyCba_1.AddDynamic(this, &ABountyDirector::BuyCustomBountyAlteration_1);
	PC_Display->BuyCba_2.AddDynamic(this, &ABountyDirector::BuyCustomBountyAlteration_2);
	PC_Display->BuyCba_3.AddDynamic(this, &ABountyDirector::BuyCustomBountyAlteration_3);
	PC_Display->BuyAmmoDrop.AddDynamic(this, &ABountyDirector::BuyAmmoDrop);
	PC_Display->BuyHealthDrop.AddDynamic(this, &ABountyDirector::BuyHealthDrop);
	PC_Display->BuyRadio.AddDynamic(this, &ABountyDirector::BuyEnemyRadio);
	PC_Display->BuyFavour.AddDynamic(this, &ABountyDirector::BuyFavours);
	
	PC_Display->LoadOS();
}

void ABountyDirector::InteractPrompt()
{

}

void ABountyDirector::DestroyBountyDirectorPCWidget()
{
	if (IsValid(PC_DisplayWidget)) PC_DisplayWidget->RemoveFromParent();

	FInputModeGameOnly InputMode;
	APlayerController* PlayerController = GetWorld()->GetFirstPlayerController();
	PlayerController->SetInputMode(InputMode);
	PlayerController->bShowMouseCursor = false;
	PlayerController->bEnableClickEvents = false;
	PlayerController->bEnableMouseOverEvents = false;
}


