#pragma once

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

USTRUCT(BlueprintType)
struct FHyperTwistMagic120CellRuntimeState
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Magic120Cell")
	FString StateProfile = TEXT("magic120cell-7560-facelet-permutation-v1");

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

	/** Destination slot to solved-cell color index for all 120 x 63 stickers. */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Magic120Cell")
	TArray<int32> StickerColorIndices;

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

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

	bool IsStructurallyValid() const;
};

USTRUCT(BlueprintType)
struct FHyperTwistMagic120CellTurnRequest
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Magic120Cell")
	int32 CellIndex = 0;

	/** 1-12 face axes, 13-42 edge axes, and 43-62 vertex axes. */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Magic120Cell")
	int32 StickerIndex = 1;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Magic120Cell")
	bool bInverse = false;

	bool IsStructurallyValid() const;
};

USTRUCT(BlueprintType)
struct FHyperTwistMagic120CellTurnResult
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Magic120Cell")
	FHyperTwistMagic120CellRuntimeState State;

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

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

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Magic120Cell")
	int32 MovedStickerCount = 0;

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

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

USTRUCT(BlueprintType)
struct FHyperTwistMagic120CellScrambleResult
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Magic120Cell")
	FHyperTwistMagic120CellRuntimeState State;

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

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

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

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

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

USTRUCT(BlueprintType)
struct FHyperTwistMagic120CellProjectedCell
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Magic120Cell")
	int32 CellIndex = INDEX_NONE;

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

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Magic120Cell")
	int32 RepresentativeColorIndex = INDEX_NONE;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Magic120Cell")
	int32 DisplacedStickerCount = 0;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Magic120Cell")
	bool bCellSolved = true;

	bool IsStructurallyValid() const;
};

USTRUCT(BlueprintType)
struct FHyperTwistMagic120CellProjection
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Magic120Cell")
	FString ProjectionProfile = TEXT("magic120cell-120-cell-7560-facelet-projection-v1");

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Magic120Cell")
	TArray<FHyperTwistMagic120CellProjectedCell> Cells;

	bool IsStructurallyValid() const;
};

USTRUCT(BlueprintType)
struct FHyperTwistMagic120CellProjectionBuildResult
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Magic120Cell")
	FHyperTwistMagic120CellProjection Projection;

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

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

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

/**
 * Exact runtime behavior is derived from the MIT-licensed roice3/Magic120Cell
 * move engine. Copyright (c) 2016 Roice Nelson.
 */
UCLASS()
class UNREALHYPERTWIST_API UHyperTwistMagic120CellRuntimeLibrary
	: public UBlueprintFunctionLibrary
{
	GENERATED_BODY()

public:
	UFUNCTION(BlueprintPure, Category = "HyperTwist|Magic120Cell")
	static FHyperTwistPuzzleDefinitionRef MakePuzzleDefinition();

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Magic120Cell")
	static FHyperTwistMagic120CellRuntimeState BuildSolvedState();

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

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Magic120Cell")
	static FHyperTwistMagic120CellTurnResult ApplyTurn(
		const FHyperTwistMagic120CellRuntimeState& State,
		const FHyperTwistMagic120CellTurnRequest& Request
	);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Magic120Cell")
	static FHyperTwistMagic120CellScrambleResult GenerateScramble(
		int32 MoveCount = 100,
		int32 RandomSeed = 2027
	);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Magic120Cell")
	static FHyperTwistMagic120CellProjectionBuildResult BuildProjection(
		const FHyperTwistMagic120CellRuntimeState& State
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Magic120Cell")
	static int32 GetTurnOrderForSticker(int32 StickerIndex);

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

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

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Magic120Cell")
	static bool IsPermutationTableReady(FString& OutError);
};
