#pragma once

// Clean-room implementation for HyperTwist algorithm-language subsystem
// Implemented from governance docs only (Phase 0R-D, Phase 1R, Phase 5R-A)
// Source: Behavioral contracts from cubing/alg.js Model A handoff (GPL-3.0-or-later lane)
//         No source code inspection. Clean-room workflow only.
// Date: 2026-05-15
// Bound 1 (initial types + structural equality) — structural UHT fix applied in Bound 2 pass:
//   Removed UPROPERTY from recursive TArray fields (Group.Inner, Commutator/Conjugate A/B)
//   because UHT cannot resolve circular USTRUCT references. Those fields remain accessible
//   in C++ but are not Blueprint-exposed. All non-recursive fields retain UPROPERTY.

#include "CoreMinimal.h"
#include "HyperTwistAlgorithmTypes.generated.h"

// ---------------------------------------------------------------------------
// Enums
// ---------------------------------------------------------------------------

UENUM(BlueprintType)
enum class EHyperTwistAlgorithmNodeType : uint8
{
	Sequence    UMETA(DisplayName = "Sequence"),
	Group       UMETA(DisplayName = "Group"),
	BlockMove   UMETA(DisplayName = "BlockMove"),
	Commutator  UMETA(DisplayName = "Commutator"),
	Conjugate   UMETA(DisplayName = "Conjugate"),
	Pause       UMETA(DisplayName = "Pause"),
	Newline     UMETA(DisplayName = "Newline"),
	Comment     UMETA(DisplayName = "Comment")
};

UENUM(BlueprintType)
enum class EHyperTwistAlgorithmMoveType : uint8
{
	Plain         UMETA(DisplayName = "Plain"),       // no explicit layer prefix
	InnerSlice    UMETA(DisplayName = "InnerSlice"),  // N + family, e.g. 2R or 3Rw
	RangedSlice   UMETA(DisplayName = "RangedSlice"), // A-B + family, e.g. 2-3Uw
	WideMove      UMETA(DisplayName = "WideMove")     // legacy wide encoding retained for compatibility
};

UENUM(BlueprintType)
enum class EHyperTwistAlgorithmCommentType : uint8
{
	Line  UMETA(DisplayName = "Line"),
	Block UMETA(DisplayName = "Block")
};

// ---------------------------------------------------------------------------
// BlockMove — a single atomic move (Plain, InnerSlice, RangedSlice, or WideMove)
// ---------------------------------------------------------------------------

USTRUCT(BlueprintType)
struct FHyperTwistAlgorithmBlockMove
{
	GENERATED_BODY()

	// Face / axis family: "R", "U", "D", "L", "F", "B", "M", "E", "S", "x", "y", "z", etc.
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Algorithm")
	FString Family;

	// Turn amount: 1 = quarter CW, -1 = quarter CCW (prime), 2 = half, -2 = half prime, 3 = three-quarter CW
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Algorithm")
	int32 Amount = 1;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Algorithm")
	EHyperTwistAlgorithmMoveType MoveType = EHyperTwistAlgorithmMoveType::Plain;

	// Wide-turn marker carried separately from the layer-prefix mode so that
	// notations such as 3Rw and 2-3Uw can be represented without losing the
	// prefix information. The older WideMove enum value remains readable for
	// compatibility with earlier local work-in-progress states.
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Algorithm")
	bool bIsWide = false;

	// InnerSlice: the affected layer index (1-based). e.g. "2R" → InnerLayer=2.
	// RangedSlice: the start of the range. e.g. "3-5Uw" → InnerLayer=3, OuterLayer=5.
	// WideMove: OuterLayer = number of layers (default 2 for plain "Rw").
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Algorithm")
	int32 InnerLayer = 0;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Algorithm")
	int32 OuterLayer = 0;

	bool UsesWideSuffix() const
	{
		return bIsWide || MoveType == EHyperTwistAlgorithmMoveType::WideMove;
	}

	EHyperTwistAlgorithmMoveType GetCanonicalMoveType() const
	{
		if (MoveType == EHyperTwistAlgorithmMoveType::WideMove)
		{
			return OuterLayer > 2
				? EHyperTwistAlgorithmMoveType::InnerSlice
				: EHyperTwistAlgorithmMoveType::Plain;
		}

		return MoveType;
	}

	int32 GetCanonicalInnerLayer() const
	{
		if (MoveType == EHyperTwistAlgorithmMoveType::WideMove && OuterLayer > 2)
		{
			return OuterLayer;
		}

		return InnerLayer;
	}

	int32 GetCanonicalOuterLayer() const
	{
		if (MoveType == EHyperTwistAlgorithmMoveType::WideMove)
		{
			return 0;
		}

		return OuterLayer;
	}

	bool operator==(const FHyperTwistAlgorithmBlockMove& Other) const
	{
		return Family == Other.Family
			&& Amount == Other.Amount
			&& UsesWideSuffix() == Other.UsesWideSuffix()
			&& GetCanonicalMoveType() == Other.GetCanonicalMoveType()
			&& GetCanonicalInnerLayer() == Other.GetCanonicalInnerLayer()
			&& GetCanonicalOuterLayer() == Other.GetCanonicalOuterLayer();
	}
};

// ---------------------------------------------------------------------------
// FHyperTwistAlgorithmNode — forward declaration required before composite types
// (Because Group, Commutator, Conjugate all reference it.)
// ---------------------------------------------------------------------------

struct FHyperTwistAlgorithmNode;

// ---------------------------------------------------------------------------
// Composite sub-types
// NOTE on UPROPERTY: The Inner/A/B arrays hold FHyperTwistAlgorithmNode, which
// would create a circular USTRUCT reference that UHT cannot resolve. Those fields
// are therefore NOT tagged as UPROPERTY. They are fully accessible in C++ and are
// correctly serialized by the first-party algorithm library; they simply cannot be
// directly exposed to Blueprints as nested properties.
// ---------------------------------------------------------------------------

USTRUCT(BlueprintType)
struct FHyperTwistAlgorithmGroup
{
	GENERATED_BODY()

	// NOT a UPROPERTY — recursive USTRUCT array; UHT cannot resolve circular reference.
	TArray<FHyperTwistAlgorithmNode> Inner;

	// Repeat count. Positive = repeat that many times. The expander handles the repetition.
	// Negative values represent the inverse direction of the repeated content.
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Algorithm")
	int32 Amount = 1;
};

USTRUCT(BlueprintType)
struct FHyperTwistAlgorithmCommutator
{
	GENERATED_BODY()

	// NOT a UPROPERTY — recursive USTRUCT array.
	// [A, B] expands to: A B A⁻¹ B⁻¹
	TArray<FHyperTwistAlgorithmNode> A;
	TArray<FHyperTwistAlgorithmNode> B;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Algorithm")
	int32 Amount = 1;
};

USTRUCT(BlueprintType)
struct FHyperTwistAlgorithmConjugate
{
	GENERATED_BODY()

	// NOT a UPROPERTY — recursive USTRUCT array.
	// [A: B] expands to: A B A⁻¹
	TArray<FHyperTwistAlgorithmNode> A;
	TArray<FHyperTwistAlgorithmNode> B;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Algorithm")
	int32 Amount = 1;
};

USTRUCT(BlueprintType)
struct FHyperTwistAlgorithmComment
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Algorithm")
	EHyperTwistAlgorithmCommentType CommentType = EHyperTwistAlgorithmCommentType::Line;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Algorithm")
	FString CommentText;
};

// ---------------------------------------------------------------------------
// FHyperTwistAlgorithmNode — discriminated union over all node types
// ---------------------------------------------------------------------------

USTRUCT(BlueprintType)
struct FHyperTwistAlgorithmNode
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Algorithm")
	EHyperTwistAlgorithmNodeType NodeType = EHyperTwistAlgorithmNodeType::BlockMove;

	// Active field depends on NodeType. Only one is meaningful per node.
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Algorithm")
	FHyperTwistAlgorithmBlockMove BlockMove;

	// Group, Commutator, Conjugate hold recursive arrays — see sub-type comments above.
	FHyperTwistAlgorithmGroup Group;
	FHyperTwistAlgorithmCommutator Commutator;
	FHyperTwistAlgorithmConjugate Conjugate;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Algorithm")
	FHyperTwistAlgorithmComment Comment;

	bool operator==(const FHyperTwistAlgorithmNode& Other) const;
};

// ---------------------------------------------------------------------------
// FHyperTwistAlgorithmSequence — top-level container for a parsed algorithm
// ---------------------------------------------------------------------------

USTRUCT(BlueprintType)
struct FHyperTwistAlgorithmSequence
{
	GENERATED_BODY()

	// NOT a UPROPERTY — recursive USTRUCT array (nodes may contain sub-sequences).
	TArray<FHyperTwistAlgorithmNode> Nodes;

	bool operator==(const FHyperTwistAlgorithmSequence& Other) const
	{
		if (Nodes.Num() != Other.Nodes.Num())
		{
			return false;
		}

		for (int32 Index = 0; Index < Nodes.Num(); ++Index)
		{
			if (!(Nodes[Index] == Other.Nodes[Index]))
			{
				return false;
			}
		}

		return true;
	}
};

// ---------------------------------------------------------------------------
// FHyperTwistAlgorithmParseResult — output of UHyperTwistAlgorithmParser
// ---------------------------------------------------------------------------

USTRUCT(BlueprintType)
struct FHyperTwistAlgorithmParseResult
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Algorithm")
	bool bSuccess = false;

	// Valid when bSuccess == true.
	FHyperTwistAlgorithmSequence Sequence;

	// Valid when bSuccess == false.
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Algorithm")
	FString ErrorMessage;

	// Character position where parsing failed. -1 if not applicable.
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Algorithm")
	int32 ErrorPosition = -1;
};
