#pragma once

#include "CoreMinimal.h"
#include "HyperTwistClassicCubeTypes.generated.h"

UENUM(BlueprintType)
enum class EHyperTwistClassicCubeFace : uint8
{
	Up     UMETA(DisplayName = "Up"),
	Down   UMETA(DisplayName = "Down"),
	Front  UMETA(DisplayName = "Front"),
	Back   UMETA(DisplayName = "Back"),
	Left   UMETA(DisplayName = "Left"),
	Right  UMETA(DisplayName = "Right")
};

UENUM(BlueprintType)
enum class EHyperTwistRotationDirection : uint8
{
	Clockwise        UMETA(DisplayName = "Clockwise"),
	CounterClockwise UMETA(DisplayName = "Counter-Clockwise")
};

UENUM(BlueprintType)
enum class EHyperTwistClassicCubeSessionMode : uint8
{
	FreePlay UMETA(DisplayName = "Free Play"),
	FollowAlong UMETA(DisplayName = "Follow Along")
};

UENUM(BlueprintType)
enum class EHyperTwistClassicCubeVoiceCommandKind : uint8
{
	None UMETA(DisplayName = "None"),
	Unsupported UMETA(DisplayName = "Unsupported"),
	Move UMETA(DisplayName = "Move"),
	NewScramble UMETA(DisplayName = "New Scramble"),
	RequestHint UMETA(DisplayName = "Request Hint"),
	SubmitSolve UMETA(DisplayName = "Submit Solve"),
	ToggleFollowAlong UMETA(DisplayName = "Toggle Follow Along"),
	CycleVoiceProfile UMETA(DisplayName = "Cycle Voice Profile"),
	ReadyCoach UMETA(DisplayName = "Ready Coach")
};

USTRUCT(BlueprintType)
struct FHyperTwistClassicCubeMoveDescriptor
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Cube")
	EHyperTwistClassicCubeFace Face = EHyperTwistClassicCubeFace::Up;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Cube")
	EHyperTwistRotationDirection Direction = EHyperTwistRotationDirection::Clockwise;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Cube")
	int32 QuarterTurns = 1;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Cube")
	FString Notation;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Cube")
	bool bGameplayMove = false;

	bool IsStructurallyValid() const
	{
		return QuarterTurns > 0 && !Notation.IsEmpty();
	}
};

USTRUCT(BlueprintType)
struct FHyperTwistClassicCubeVoiceCommand
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Cube")
	EHyperTwistClassicCubeVoiceCommandKind CommandKind =
		EHyperTwistClassicCubeVoiceCommandKind::None;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Cube")
	FHyperTwistClassicCubeMoveDescriptor Move;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Cube")
	FString TranscriptText;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Cube")
	FString FeedbackLine;

	bool IsStructurallyValid() const
	{
		switch (CommandKind)
		{
		case EHyperTwistClassicCubeVoiceCommandKind::Move:
			return Move.IsStructurallyValid() && !TranscriptText.IsEmpty();
		case EHyperTwistClassicCubeVoiceCommandKind::Unsupported:
			return !TranscriptText.IsEmpty() && !FeedbackLine.IsEmpty();
		case EHyperTwistClassicCubeVoiceCommandKind::None:
			return false;
		default:
			return !TranscriptText.IsEmpty();
		}
	}
};

USTRUCT(BlueprintType)
struct FHyperTwistClassicCubePieceData
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Cube")
	FVector GridPosition = FVector::ZeroVector;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Cube")
	TArray<EHyperTwistClassicCubeFace> ColoredFaces;
};

USTRUCT(BlueprintType)
struct FHyperTwistClassicCubeReplayMetadata
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Cube")
	FString PuzzleId = TEXT("cube/3x3x3");

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Cube")
	FString ScrambleNotation;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Cube")
	int32 ScrambleLength = 0;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Cube")
	EHyperTwistClassicCubeSessionMode SessionMode = EHyperTwistClassicCubeSessionMode::FreePlay;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Cube")
	FString VoiceProfileId;

	bool IsStructurallyValid() const
	{
		return !PuzzleId.IsEmpty() && ScrambleLength >= 0;
	}
};
