#pragma once

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

USTRUCT(BlueprintType)
struct FHyperTwistNotationNormalizationResult
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	FString InputNotation;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	FString NormalizedNotation;

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

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	bool bIsValid = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	bool bWasModified = false;
};

USTRUCT(BlueprintType)
struct FHyperTwistApplyTransformationResult
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	FHyperTwistPuzzleState State;

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

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

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

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

USTRUCT(BlueprintType)
struct FHyperTwistPuzzleStateValidationResult
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	TArray<FString> Errors;

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

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	bool bStateSupported = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	bool bStructureValid = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	bool bPermutationParityEven = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	bool bOrientationParityCompatible = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	bool bTwistConserved = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	bool bIsSolvable = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	int32 TwistBalance = 0;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	int32 OrientationParityMismatchCount = 0;
};

USTRUCT(BlueprintType)
struct FHyperTwistRandomStateGenerationResult
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	FHyperTwistPuzzleState State;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	FHyperTwistPuzzleStateValidationResult Validation;

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

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	int32 SeedUsed = 0;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	int32 AttemptsUsed = 0;

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

USTRUCT(BlueprintType)
struct FHyperTwistTransformationInversionResult
{
	GENERATED_BODY()

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

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

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	bool bInverted = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	bool bExactInverse = false;
};

USTRUCT(BlueprintType)
struct FHyperTwistTransformationCompositionResult
{
	GENERATED_BODY()

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

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

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	bool bComposed = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	bool bExactComposition = false;
};

USTRUCT(BlueprintType)
struct FHyperTwistMelindaScramblePacketBuildResult
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	FHyperTwistMelinda2x2x2x2ScramblePacket Packet;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	FHyperTwistPuzzleStateValidationResult TargetStateValidation;

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

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

USTRUCT(BlueprintType)
struct FHyperTwistMelindaFlatProjectionBuildResult
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	FHyperTwistMelinda2x2x2x2FlatProjection Projection;

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

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

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

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

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

public:
	UFUNCTION(BlueprintPure, Category = "HyperTwist|Core")
	static FHyperTwistNotationNormalizationResult NormalizeNotation(const FString& RawNotation);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Core")
	static bool TryCanonicalizeAlgorithmNotation(
		const FString& RawNotation,
		FString& OutCanonicalNotation,
		FString& OutErrorMessage,
		int32& OutErrorPosition
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Core")
	static bool IsSolved(const FHyperTwistPuzzleState& State);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Validation")
	static FHyperTwistPuzzleStateValidationResult ValidatePuzzleState(const FHyperTwistPuzzleState& State);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Core")
	static FHyperTwistRandomStateGenerationResult GenerateRandomPuzzleState(
		const FHyperTwistPuzzleDefinitionRef& Definition,
		int32 RandomSeed
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Core")
	static FHyperTwistTransformationInversionResult InvertTransformation(const FHyperTwistTransformation& Transformation);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Core")
	static FHyperTwistTransformationCompositionResult ComposeTransformations(
		const FHyperTwistTransformation& FirstTransformation,
		const FHyperTwistTransformation& SecondTransformation
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Scramble")
	static FHyperTwistMelindaScramblePacketBuildResult BuildMelindaScramblePacketFromGeneratedState(
		const FHyperTwistRandomStateGenerationResult& GeneratedStateResult
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Scramble")
	static FHyperTwistMelindaScramblePacketBuildResult BuildMelindaScramblePacketFromTransformSequence(
		const FHyperTwistPuzzleDefinitionRef& Definition,
		const TArray<FHyperTwistTransformation>& TransformSequence
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Debug")
	static FHyperTwistMelindaFlatProjectionBuildResult BuildMelindaFlatProjection(
		const FHyperTwistPuzzleState& State,
		const FHyperTwistMelindaFlatProjectionOptions& Options
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Core")
	static FHyperTwistApplyTransformationResult ApplyTransformation(const FHyperTwistPuzzleState& State, const FHyperTwistTransformation& Transformation);
};
