#pragma once

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

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

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

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

USTRUCT(BlueprintType)
struct FHyperTwistMelindaCellTurnRequest
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Melinda")
	EHyperTwistMelindaCell Cell = EHyperTwistMelindaCell::Outer;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Melinda")
	EHyperTwistMelindaCellAxis RotationAxis = EHyperTwistMelindaCellAxis::X;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Melinda")
	EHyperTwistMelindaTurnDirection Direction = EHyperTwistMelindaTurnDirection::Clockwise;
};

USTRUCT(BlueprintType)
struct FHyperTwistMelindaCellTurnTransformBuildResult
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Melinda")
	FHyperTwistTransformation Transformation;

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

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Melinda")
	bool bBuilt = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Melinda")
	bool bExactTransform = false;
};

USTRUCT(BlueprintType)
struct FHyperTwistMelindaProjectedCubieFace
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Melinda")
	EHyperTwistMelindaCellAxis Axis = EHyperTwistMelindaCellAxis::X;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Melinda")
	bool bPositiveSide = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Melinda")
	EHyperTwistMelindaStickerColor Color = EHyperTwistMelindaStickerColor::Unknown;

	bool IsStructurallyValid() const
	{
		return Color != EHyperTwistMelindaStickerColor::Unknown;
	}
};

USTRUCT(BlueprintType)
struct FHyperTwistMelindaProjectedCubie
{
	GENERATED_BODY()

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

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

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Melinda")
	FIntVector LocalGridCoordinate = FIntVector::ZeroValue;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Melinda")
	FString SlotLabel;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Melinda")
	FString PieceLabel;

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

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Melinda")
	TArray<FHyperTwistMelindaProjectedCubieFace> Faces;

	bool IsStructurallyValid() const;
};

USTRUCT(BlueprintType)
struct FHyperTwistMelindaProjectedCell
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Melinda")
	EHyperTwistMelindaCell Cell = EHyperTwistMelindaCell::Outer;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Melinda")
	EHyperTwistMelindaCellAxis FixedAxis = EHyperTwistMelindaCellAxis::W;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Melinda")
	bool bPositiveSide = true;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Melinda")
	FString CellLabel;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Melinda")
	FVector DisplayCenter = FVector::ZeroVector;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Melinda")
	TArray<EHyperTwistMelindaCellAxis> AvailableAxes;

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

	bool IsStructurallyValid() const;
};

USTRUCT(BlueprintType)
struct FHyperTwistMelindaCellFirstProjection
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Melinda")
	FString ProjectionProfile = TEXT("melinda-2x2x2x2-cell-first-projection-v1");

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

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

	bool IsStructurallyValid() const;
};

USTRUCT(BlueprintType)
struct FHyperTwistMelindaCellFirstProjectionBuildResult
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Melinda")
	FHyperTwistMelindaCellFirstProjection Projection;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Melinda")
	FHyperTwistPuzzleStateValidationResult SourceStateValidation;

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

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

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

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

public:
	UFUNCTION(BlueprintPure, Category = "HyperTwist|Melinda")
	static FString GetCellLabel(EHyperTwistMelindaCell Cell);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Melinda")
	static FString GetAxisLabel(EHyperTwistMelindaCellAxis Axis);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Melinda")
	static bool IsAxisAvailableForCell(EHyperTwistMelindaCell Cell, EHyperTwistMelindaCellAxis Axis);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Melinda")
	static TArray<EHyperTwistMelindaCellAxis> GetAvailableAxesForCell(EHyperTwistMelindaCell Cell);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Melinda")
	static FHyperTwistMelindaCellTurnTransformBuildResult BuildCellTurnTransformation(
		const FHyperTwistPuzzleDefinitionRef& Definition,
		const FHyperTwistMelindaCellTurnRequest& Request
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Melinda")
	static FHyperTwistMelindaCellFirstProjectionBuildResult BuildCellFirstProjection(
		const FHyperTwistPuzzleState& State,
		float CellCenterSpacing = 120.0f
	);
};
