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

#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "CoffeeMachineController.generated.h"

class UHoverableBoxComponent;
class AFayePlayerController;

const FName OBJECT_TYPE_PORTAFILTER("Portafilter");
const FName OBJECT_TYPE_TAMPER("Tamper");
const FName OBJECT_TYPE_GRINDER("Grinder");
const FName OBJECT_TYPE_MAIN_COFFEE_MACHINE("MainCoffeeMachine");
const FName OBJECT_TYPE_GRINDER_BUTTON("GrinderButton");
const FName OBJECT_TYPE_MAIN_MACHINE_BUTTON("MainMachineButton");
const FName OBJECT_TYPE_COFFEE_MUG("CoffeeMug");

DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnObjectReleased);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnObjectClicked);

UENUM()
enum class EInputControllerType : uint8
{
	Mouse,
	Touch,
	Gamepad
};

UENUM(BlueprintType)
enum class ECoffeeMachineMakingState : uint8
{
	Start,
	PortafilterDragging,
	PortafilterFilling,
	PortafilterPressing,
	CoffeeLoaded,
	CoffeeFilling,
	CoffeeReady,
	WaitingAction				UMETA(ToolTip = "Use when you don't wanna be able to hover anythig")
};

UENUM()
enum class ECoffeeMachinePropMovementMode : uint8
{
	PlaneYZ,
	ZOnly
};

UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent), Blueprintable)
class FAYE_API UCoffeeMachineController : public UActorComponent
{
	GENERATED_BODY()

public:
	UCoffeeMachineController();
	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
	void ToggleCoffeeMaking(bool bActive);
	bool IsCoffeeMakingActive() const { return bCoffeeMakingActive; }
	
	UFUNCTION(BLueprintPure)
	UHoverableBoxComponent* GetCurrentHoverableComponent() const { return CurrentHoverableComponent; }
	
	UFUNCTION(BlueprintPure)
	UStaticMeshComponent* GetCurrentSelectedMeshComponent() const { return CurrentSelectedMeshComponent; }
	
	UFUNCTION(BlueprintPure)
	UHoverableBoxComponent* GetCurrentSelectedBoxComponent() const { return CurrentSelectedBoxComponent; }
	
	// Currently selected object will be nulled so cache if you need
	UPROPERTY(BlueprintAssignable)
	FOnObjectReleased OnObjectReleased;
	
	UPROPERTY(BlueprintAssignable)
	FOnObjectClicked OnObjectClicked;
	
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	bool bCupPlaced = false;
	
	UFUNCTION(BlueprintCallable)
	void SetCoffeeMakingStage(ECoffeeMachineMakingState NewStage);
	UFUNCTION(BlueprintPure)
	ECoffeeMachineMakingState GetCoffeeMakingStage() const { return CurrentCoffeeMakingStage; }
	
	UFUNCTION(BlueprintCallable)
	void SetTamperLiftStartingPos(FVector NewPos) { TamperLiftStartingPos = NewPos; }

	
protected:
	virtual void BeginPlay() override;

	UPROPERTY()
	AFayePlayerController* PlayerController;
	
	ECoffeeMachineMakingState CurrentCoffeeMakingStage = ECoffeeMachineMakingState::Start;
	bool bCoffeeMakingActive = false;
	bool bHoldingPortafilter = false;
	
	ECoffeeMachinePropMovementMode CurrentGrabbedObjectMovementMode;
	FVector CurrentGrabbedObjectStartPos;
	FVector TamperLiftStartingPos;
	
	UPROPERTY()
	UHoverableBoxComponent* CurrentHoverableComponent = nullptr;
	
	UPROPERTY()
	UStaticMeshComponent* CurrentSelectedMeshComponent = nullptr;
	UPROPERTY()
	UHoverableBoxComponent* CurrentSelectedBoxComponent = nullptr;
	
	EInputControllerType InputType = EInputControllerType::Mouse;
	
	void PerformMouseHover();
	void MoveHeldObject();
	
	void HoverBox(UHoverableBoxComponent* InBox);
	bool GrabObject(UHoverableBoxComponent* InBox);
	void ReleaseObject();
	bool CanGrab(const UHoverableBoxComponent* InBox) const;
	bool CanHover(const UHoverableBoxComponent* InBox) const;
	
	UFUNCTION()
	void OnInputGrab();
	UFUNCTION()
	void OnInputRelease();
};
