#pragma once

#include "CoreMinimal.h"
#include "HyperTwistCore/HyperTwistCoreLibrary.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "HyperTwistMagicCube5DRuntimeLibrary.generated.h"

UENUM(BlueprintType)
enum class EHyperTwistMagicCube5DAxis : uint8
{
	X UMETA(DisplayName = "X"),
	Y UMETA(DisplayName = "Y"),
	Z UMETA(DisplayName = "Z"),
	W UMETA(DisplayName = "W"),
	V UMETA(DisplayName = "V")
};

UENUM(BlueprintType)
enum class EHyperTwistMagicCube5DTurnDirection : uint8
{
	PositiveQuarterTurn UMETA(DisplayName = "Positive Quarter Turn"),
	NegativeQuarterTurn UMETA(DisplayName = "Negative Quarter Turn")
};

USTRUCT(BlueprintType)
struct FHyperTwistMagicCube5DSignedAxis
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	EHyperTwistMagicCube5DAxis Axis = EHyperTwistMagicCube5DAxis::X;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	bool bPositiveDirection = true;
};

USTRUCT(BlueprintType)
struct FHyperTwistMagicCube5DPieceOrientation
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	TArray<FHyperTwistMagicCube5DSignedAxis> Basis;

	bool IsStructurallyValid() const;
};

USTRUCT(BlueprintType)
struct FHyperTwistMagicCube5DGridCoordinate
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	TArray<int32> Components;

	bool IsValidForOrder(int32 Order) const;
};

USTRUCT(BlueprintType)
struct FHyperTwistMagicCube5DRuntimeState
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	FString StateProfile = TEXT("magiccube5d-order-3-piece-orientation-v1");

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	FHyperTwistPuzzleDefinitionRef Definition;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	int32 Order = 3;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	TArray<int32> PositionToPiece;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	TArray<FHyperTwistMagicCube5DPieceOrientation> PieceOrientations;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	int32 AppliedMoveCount = 0;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	bool bIsSolved = true;

	bool IsStructurallyValid() const;
	int32 GetPieceCount() const;
};

USTRUCT(BlueprintType)
struct FHyperTwistMagicCube5DTurnRequest
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	EHyperTwistMagicCube5DAxis FaceAxis = EHyperTwistMagicCube5DAxis::V;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	bool bPositiveFace = true;

	/** Bit zero is the outer face layer; subsequent bits select inward layers. */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	int32 SliceMask = 1;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	EHyperTwistMagicCube5DAxis RotationAxisA = EHyperTwistMagicCube5DAxis::X;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	EHyperTwistMagicCube5DAxis RotationAxisB = EHyperTwistMagicCube5DAxis::Y;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	EHyperTwistMagicCube5DTurnDirection Direction =
		EHyperTwistMagicCube5DTurnDirection::PositiveQuarterTurn;

	bool IsValidForOrder(int32 Order) const;
};

USTRUCT(BlueprintType)
struct FHyperTwistMagicCube5DTurnResult
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	FHyperTwistMagicCube5DRuntimeState State;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	FString AppliedNotation;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	TArray<FString> Warnings;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	bool bApplied = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	bool bExactStateUpdate = false;
};

USTRUCT(BlueprintType)
struct FHyperTwistMagicCube5DScrambleResult
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	FHyperTwistMagicCube5DRuntimeState State;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	TArray<FHyperTwistMagicCube5DTurnRequest> Moves;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	TArray<FString> AppliedNotation;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	TArray<FString> Warnings;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	bool bGenerated = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	bool bExactStateUpdate = false;
};

USTRUCT(BlueprintType)
struct FHyperTwistMagicCube5DProjectedCubie
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	int32 PositionIndex = INDEX_NONE;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	int32 PieceId = INDEX_NONE;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	FHyperTwistMagicCube5DGridCoordinate Position;

	/** The first outward-facing sticker color, or INDEX_NONE for an internal cubie. */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	int32 RepresentativeColorIndex = INDEX_NONE;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	bool bPieceInSolvedPosition = false;

	bool IsStructurallyValid(int32 Order) const;
};

USTRUCT(BlueprintType)
struct FHyperTwistMagicCube5DProjectedFacelet
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	int32 PositionIndex = INDEX_NONE;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	int32 PieceId = INDEX_NONE;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	EHyperTwistMagicCube5DAxis WorldAxis = EHyperTwistMagicCube5DAxis::X;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	bool bPositiveWorldSide = true;

	/** Solved colors are X-/X+/Y-/Y+/Z-/Z+/W-/W+/V-/V+. */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	int32 ColorIndex = INDEX_NONE;

	bool IsStructurallyValid(int32 PieceCount) const;
};

USTRUCT(BlueprintType)
struct FHyperTwistMagicCube5DProjection
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	FString ProjectionProfile = TEXT("magiccube5d-boundary-facelet-projection-v1");

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	int32 Order = 3;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	TArray<FHyperTwistMagicCube5DProjectedCubie> Cubies;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	TArray<FHyperTwistMagicCube5DProjectedFacelet> Facelets;

	bool IsStructurallyValid() const;
};

USTRUCT(BlueprintType)
struct FHyperTwistMagicCube5DProjectionBuildResult
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	FHyperTwistMagicCube5DProjection Projection;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	TArray<FString> Warnings;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	bool bProjected = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|MagicCube5D")
	bool bExactProjection = false;
};

UCLASS()
class UNREALHYPERTWIST_API UHyperTwistMagicCube5DRuntimeLibrary
	: public UBlueprintFunctionLibrary
{
	GENERATED_BODY()

public:
	UFUNCTION(BlueprintPure, Category = "HyperTwist|MagicCube5D")
	static bool IsSupportedOrder(int32 Order);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|MagicCube5D")
	static FHyperTwistPuzzleDefinitionRef MakePuzzleDefinition(int32 Order = 3);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|MagicCube5D")
	static FHyperTwistMagicCube5DRuntimeState BuildSolvedState(int32 Order = 3);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|MagicCube5D")
	static FHyperTwistPuzzleState BuildPuzzleStateEnvelope(
		const FHyperTwistMagicCube5DRuntimeState& RuntimeState
	);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|MagicCube5D")
	static FHyperTwistMagicCube5DTurnResult ApplyTurn(
		const FHyperTwistMagicCube5DRuntimeState& State,
		const FHyperTwistMagicCube5DTurnRequest& Request
	);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|MagicCube5D")
	static FHyperTwistMagicCube5DScrambleResult GenerateScramble(
		int32 Order = 3,
		int32 MoveCount = 60,
		int32 RandomSeed = 2027
	);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|MagicCube5D")
	static FHyperTwistMagicCube5DProjectionBuildResult BuildProjection(
		const FHyperTwistMagicCube5DRuntimeState& State
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|MagicCube5D")
	static FString SerializeRuntimeStateToJson(
		const FHyperTwistMagicCube5DRuntimeState& RuntimeState
	);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|MagicCube5D")
	static bool TryDeserializeRuntimeStateFromJson(
		const FString& Json,
		FHyperTwistMagicCube5DRuntimeState& OutRuntimeState
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|MagicCube5D")
	static FString GetAxisLabel(EHyperTwistMagicCube5DAxis Axis);
};
