// Oleg Petruny proprietary.

#include "MainGameModeBase.h"

#include "Engine/World.h"
#include "GameFramework/SpectatorPawn.h"
#include "Kismet/GameplayStatics.h"
#include "UObject/ScriptInterface.h"

#include "CutsceneManager.h"
#include "DialogueManager.h"
#include "Levels/LevelBase.h"
#include "QuestManager.h"
#include "QuickTimeEvent.h"
#include "Widgets/WidgetsManager.h"

AMainGameModeBase* AMainGameModeBase::instance = nullptr;
TStrongObjectPtr<UWidgetsManager> AMainGameModeBase::widgetsManager = nullptr;
TStrongObjectPtr<UCutsceneManager> AMainGameModeBase::cutsceneManager = nullptr;
TStrongObjectPtr<UQuickTimeEventManager> AMainGameModeBase::quickTimeEventManager = nullptr;
TStrongObjectPtr<UDialogueManager> AMainGameModeBase::dialogueManager = nullptr;
TStrongObjectPtr<ALevelBase> AMainGameModeBase::leadLevel = nullptr;

void AMainGameModeBase::StartPlay()
{
    instance = this;
    widgetsManager = TStrongObjectPtr<UWidgetsManager>{ NewObject<UWidgetsManager>(this, widgetManagerClass) };
    cutsceneManager = TStrongObjectPtr<UCutsceneManager>{ NewObject<UCutsceneManager>(this) };
    quickTimeEventManager = TStrongObjectPtr<UQuickTimeEventManager>{ NewObject<UQuickTimeEventManager>(this) };
    dialogueManager = TStrongObjectPtr<UDialogueManager>{ NewObject<UDialogueManager>(this) };

    AGameModeBase::StartPlay();

    widgetsManager->Init();
}

void AMainGameModeBase::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
    cutsceneManager->LockCallback(true);
    //cutsceneManager->ClearQueue(); // condition race segfault?
}

bool AMainGameModeBase::SetPause(APlayerController* PC, FCanUnpause CanUnpauseDelegate)
{
    if(widgetsManager)
    {
        if(IsPaused())
        {
            widgetsManager->HideWidgets();
        }
        else
        {
            widgetsManager->ShowWidgets();
        }
    }

    return AGameModeBase::SetPause(PC, CanUnpauseDelegate);
}

AMainGameModeBase* AMainGameModeBase::Get()
{
    return instance;
}

UWidgetsManager* AMainGameModeBase::GetWidgetsManager()
{
    return widgetsManager.Get();
}
UCutsceneManager* AMainGameModeBase::GetCutsceneManager()
{
    return cutsceneManager.Get();
}

UQuickTimeEventManager* AMainGameModeBase::GetQuickTimeEventManager()
{
    return quickTimeEventManager.Get();
}

UDialogueManager* AMainGameModeBase::GetDialogueManager()
{
    return dialogueManager.Get();
}

void AMainGameModeBase::CallNextLevelState()
{
    if(leadLevel)
        leadLevel->CallNextState();
}

void AMainGameModeBase::CallLevelEvent(int32 id)
{
    if(leadLevel)
        leadLevel->CallEvent(id);
}

void AMainGameModeBase::UpdateQuests(TArray<FText> items)
{
    if(instance && instance->questsUpdateDelegate.IsBound())
        instance->questsUpdateDelegate.Broadcast(items);
}

void AMainGameModeBase::SwitchCameraMode()
{
    static TWeakObjectPtr<APawn> playerPawn = nullptr;

    if(auto PC = UGameplayStatics::GetPlayerController(GetWorld(), 0))
    {
        if(auto pawn = PC->GetPawn())
        {
            if(!playerPawn.IsValid())
            {
                auto spawnLoc = pawn->GetActorLocation();
                auto spawnRot = pawn->GetActorRotation();
                if(auto cameraPawn = GetWorld()->SpawnActor<APawn>(SpectatorClass, spawnLoc, spawnRot))
                {
                    playerPawn = pawn;
                    PC->Possess(cameraPawn);
                }
            }
            else
            {
                PC->Possess(playerPawn.Get());
                pawn->Destroy();
                playerPawn = nullptr;
            }
        }
    }

    if(widgetsManager.IsValid())
        widgetsManager->UpdateWidgetsOwner();
}
