// Oleg Petruny proprietary.

#pragma once

#include "UObject/Object.h"

#include "QuickTimeEvent.generated.h"

UENUM(BlueprintType)
enum class EQuickTimeEventType : uint8
{
    SinglePress,
    MultiPress,
    Hold
};

UENUM(BlueprintType)
enum class EQuickTimeEventResult : uint8
{
    Success,
    FailedTime,
    FailedKey
};

DECLARE_DYNAMIC_DELEGATE_OneParam(FQuickTimeEventEndCallback, EQuickTimeEventResult, result);

USTRUCT(BlueprintType)
struct FQuickTimeEventEnqueProperties
{
    GENERATED_BODY()

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    EQuickTimeEventType type = EQuickTimeEventType::SinglePress;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    FKey key = EKeys::F;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    float duration = 1.0f;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    FVector2D anchor = FVector2D::Unit45Deg;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    FQuickTimeEventEndCallback callback;
};

struct Event
{
public:
    Event();
    Event(EQuickTimeEventType type, FKey& key, FQuickTimeEventEndCallback& callback, bool sequence);

    inline int32 GetId();

    EQuickTimeEventType type;
    FKey key;
    FTimerHandle timer;
    FQuickTimeEventEndCallback callback;
    bool sequence;

private:
    int32 id;
    static int32 counter;
};

UCLASS(Blueprintable, BlueprintType)
class UQuickTimeEventManager : public UObject
{
    GENERATED_BODY()

public:
    UFUNCTION(BlueprintCallable)
    void ShowQuickTimeEvent(FQuickTimeEventEnqueProperties properties);

    UFUNCTION(BlueprintCallable)
    void EnqueQuickTimeEvent(FQuickTimeEventEnqueProperties properties);

protected:
    void ShowNextEvent();
    void OnEventEnd(int32 id, EQuickTimeEventResult result);

    void OnInput(const FKey& key, bool released);
    UFUNCTION()
    void OnInputPressed(FKey key);
    UFUNCTION()
    void OnInputReleased(FKey key);

    void OnFirstEventInit();
    void CreateEvent(FQuickTimeEventEnqueProperties& properties, bool sequence);

    TQueue<FQuickTimeEventEnqueProperties> nextEvents;
    TMap<int32, Event> events;
    FCriticalSection lock;
};
