// Oleg Petruny proprietary.

#pragma once

#include "GameFramework/Actor.h"

#include "Interactable.generated.h"

/** Turns on debug of interactable objects */
//#define INTERACTABLE_DEBUG
/** Turns on debug of interactable activator components */
//#define INTERACTABLE_ACTIVATOR_DEBUG
/** Turns on debug of interactable modificator components */
//#define INTERACTABLE_MODIFICATOR_DEBUG

/** Defines activation types */
UENUM(BlueprintType, meta = (Bitflags, UseEnumValuesAsMaskValuesInEditor = "true"))
enum class EActivatorType : uint8
{
    None = 0 UMETA(Hidden),
    Use = 1 << 0,
    Saw = 1 << 1,
    Collide = 1 << 2,
    Custom1 = 1 << 3 UMETA(DisplayName = "Custom 1"),
    Custom2 = 1 << 4 UMETA(DisplayName = "Custom 2"),
    Custom3 = 1 << 5 UMETA(DisplayName = "Custom 3"),
    Custom4 = 1 << 6 UMETA(DisplayName = "Custom 4"),
    Custom5 = 1 << 7 UMETA(DisplayName = "Custom 5")

};
ENUM_CLASS_FLAGS(EActivatorType);

/**
 * Object capable of reacting to activators and execute modificators.
 * Sets all needed settings as collision layers on begin play.
 */
UCLASS(Blueprintable, BlueprintType, MinimalAPI)
class AInteractable : public AActor
{
    GENERATED_BODY()

public:
    static void AppendActivatorClass(TSubclassOf<class UInteractableActivator> activator);
    static void AppendModificatorClass(TSubclassOf<class UInteractableModificator> modificator);

    /** Interactables shared cache */
    static TSet<TSubclassOf<class UInteractableActivator>> interactionActivators;
    static TSet<TSubclassOf<class UInteractableModificator>> interactionModificators;

public:

    /** Returns flags mask of activated types */
    int32 GetActivatedFlags();

    /** Receives activate signal from activator of specific type and activates all modificators of that type */
    UFUNCTION(BlueprintCallable)
    void Activate(EActivatorType type);

    /** Receives deactivate signal from activator of specific type and deactivates all modificators of that type */
    UFUNCTION(BlueprintCallable)
    void Deactivate(EActivatorType type);

    /**
     * All modificators that requires (de)activation lock for current interactable.
     * Used manually by modificators to handle operations which can be continued after physical deactivation.
     * Eg. MoveModificator movement while mouse buttons are down even if player don't activating interactable anymore.
     */
    TSet<class UInteractableModificator*> activationLockers;

protected:
    virtual void BeginPlay() override;
    virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;

    UFUNCTION(BlueprintImplementableEvent)
    void OnActivate(EActivatorType type);
    UFUNCTION(BlueprintImplementableEvent)
    void OnDeactivate(EActivatorType type);

    /** Mask of active activator types */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (Bitmask, BitmaskEnum = "EActivatorType"))
    int32 activated = 0;

    /** Map of modificators to activator types initialized on BeginPlay */
    UPROPERTY()
    TMap<EActivatorType, class UInteractableModificator*> modificators;

    TArray<UPrimitiveComponent*> collisions;
    class APlayerBase* player = nullptr;
};

