// Oleg Petruny proprietary.

#pragma once

#include "UObject/Object.h"

#include "DialogueManager.generated.h"

UENUM(BlueprintType)
enum class EDialogueWaveType : uint8
{
    Main,
    Secondary,
    Sound
};

USTRUCT(BlueprintType)
struct FDialogueRow : public FTableRowBase
{
    GENERATED_BODY()

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    TSoftObjectPtr<class USoundWave> wave = nullptr;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    EDialogueWaveType type = EDialogueWaveType::Main;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    float duration = 2.0;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    FString id = "";

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    FText text = FText::GetEmpty();
};

UENUM(BlueprintType)
enum class EDialoguePlayMode : uint8
{
    Sequential,
    ExactRow,
    Random
};

USTRUCT(BlueprintType)
struct FDialogueEnqueProperties
{
    GENERATED_BODY()

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    TSoftObjectPtr<class UDataTable> dialogue = nullptr;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    EDialoguePlayMode playMode = EDialoguePlayMode::Sequential;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    FName rowName = TEXT("1");
};

DECLARE_DYNAMIC_DELEGATE(FDialogueEndCallback);

UCLASS(BlueprintType)
class UDialogueManager : public UObject
{
    GENERATED_BODY()

public:
    UDialogueManager();

    /** Ignores play mode and force pushing dialogue */
    UFUNCTION(BlueprintCallable)
    void PlayDialogue(FDialogueEnqueProperties properties, FDialogueEndCallback endCallback);

    UFUNCTION(BlueprintCallable)
    void EnqueDialogue(FDialogueEnqueProperties properties, FDialogueEndCallback endCallback);

    UFUNCTION(BlueprintCallable)
    void SkipDialogue();

    UFUNCTION(BlueprintCallable)
    void ClearQueue();

    UFUNCTION(BlueprintCallable)
    void LockCallback(bool lock);

protected:
    virtual void BeginDestroy() override;

private:
    void PlayNextDialogue();
    void OnFirstDialogueInit();

    UFUNCTION()
    void OnDialogueEnd();

    void OnInputPress();

    TQueue<FDialogueEnqueProperties> nextDialogues;
    FCriticalSection dialoguesLock;
    TQueue<FDialogueEndCallback> endCallbacks;
    FCriticalSection callbacksLock;

    TArray<FTimerHandle> timers;
    FCriticalSection timersLock;

    int32 leadDialogueTimerId = -1;
    FDialogueEnqueProperties* leadDialogueProperties;
    class UAudioComponent* leadDialogueAudio;

    class APlayerBase* lastPlayer = nullptr;
    TSoftObjectPtr<class UInputMappingContext> context;
    int32 inputHandler;

    bool lockCallback = false;
};
