#pragma once

#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "HyperTwistTraining/HyperTwistTrainingTypes.h"
#include "HyperTwistTrainingKnowledgeLibrary.generated.h"

UENUM(BlueprintType)
enum class EHyperTwistTrainingKnowledgeNodeKind : uint8
{
	PuzzleFamily UMETA(DisplayName = "Puzzle Family"),
	Method UMETA(DisplayName = "Method"),
	Software UMETA(DisplayName = "Software"),
	Theory UMETA(DisplayName = "Theory"),
	Community UMETA(DisplayName = "Community")
};

USTRUCT(BlueprintType)
struct FHyperTwistTrainingKnowledgeTaxonomyNode
{
	GENERATED_BODY()

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

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	EHyperTwistTrainingKnowledgeNodeKind NodeKind = EHyperTwistTrainingKnowledgeNodeKind::PuzzleFamily;

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

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

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

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

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	FString NotationProfile = TEXT("hypercubing-standard");

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

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

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	FHyperTwistTrainingSourceAttribution SourceAttribution;

	bool IsStructurallyValid() const
	{
		return !NodeId.IsEmpty() && !Title.IsEmpty() && SourceAttribution.IsStructurallyValid();
	}
};

USTRUCT(BlueprintType)
struct FHyperTwistTrainingNotationReferenceTerm
{
	GENERATED_BODY()

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

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

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

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

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

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	FString NotationProfile = TEXT("hypercubing-standard");

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

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

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	FHyperTwistTrainingSourceAttribution SourceAttribution;

	bool IsStructurallyValid() const
	{
		return !TermId.IsEmpty() && !DisplayTerm.IsEmpty() && !Meaning.IsEmpty() && SourceAttribution.IsStructurallyValid();
	}
};

USTRUCT(BlueprintType)
struct FHyperTwistTrainingProgressionStageReference
{
	GENERATED_BODY()

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

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

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

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

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

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

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

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

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

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	FHyperTwistTrainingSourceAttribution SourceAttribution;

	bool IsStructurallyValid() const
	{
		return !StageId.IsEmpty() && !Title.IsEmpty() && SourceAttribution.IsStructurallyValid();
	}
};

USTRUCT(BlueprintType)
struct FHyperTwistTrainingSoftwareReference
{
	GENERATED_BODY()

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

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

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

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

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

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

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

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	FHyperTwistTrainingSourceAttribution SourceAttribution;

	bool IsStructurallyValid() const
	{
		return !SoftwareId.IsEmpty() && !Title.IsEmpty() && SourceAttribution.IsStructurallyValid();
	}
};

USTRUCT(BlueprintType)
struct FHyperTwistTrainingLeaderboardSolverProfileReference
{
	GENERATED_BODY()

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

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

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

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

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	FHyperTwistTrainingSourceAttribution SourceAttribution;

	bool IsStructurallyValid() const
	{
		return !SolverId.IsEmpty() && !DisplayName.IsEmpty() && SourceAttribution.IsStructurallyValid();
	}
};

USTRUCT(BlueprintType)
struct FHyperTwistTrainingLeaderboardEventReference
{
	GENERATED_BODY()

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

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

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

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

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

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

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

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

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	FHyperTwistTrainingSourceAttribution SourceAttribution;

	bool IsStructurallyValid() const
	{
		return !EventId.IsEmpty() && !PuzzleId.IsEmpty() && !FormatId.IsEmpty() && !Title.IsEmpty()
			&& SourceAttribution.IsStructurallyValid();
	}
};

USTRUCT(BlueprintType)
struct FHyperTwistTrainingLeaderboardDisplayPolicy
{
	GENERATED_BODY()

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

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

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

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

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

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	FHyperTwistTrainingSourceAttribution SourceAttribution;

	bool IsStructurallyValid() const
	{
		return ColumnOrder.Num() > 0
			&& !TimeFormattingRule.IsEmpty()
			&& !RelativeDateRule.IsEmpty()
			&& !SolverProfileRule.IsEmpty()
			&& !ProgramBadgeRule.IsEmpty()
			&& SourceAttribution.IsStructurallyValid();
	}
};

USTRUCT(BlueprintType)
struct FHyperTwistTrainingLeaderboardFormattedValue
{
	GENERATED_BODY()

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

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

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

	bool IsStructurallyValid() const
	{
		return !PrimaryLabel.IsEmpty() || !SecondaryLabel.IsEmpty();
	}
};

USTRUCT(BlueprintType)
struct FHyperTwistTrainingKnowledgeReferenceBundle
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	TArray<FHyperTwistTrainingKnowledgeTaxonomyNode> TaxonomyNodes;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	TArray<FHyperTwistTrainingNotationReferenceTerm> NotationTerms;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	TArray<FHyperTwistTrainingProgressionStageReference> ProgressionStages;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	TArray<FHyperTwistTrainingSoftwareReference> SoftwareReferences;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	TArray<FHyperTwistTrainingLeaderboardSolverProfileReference> SolverProfiles;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	TArray<FHyperTwistTrainingLeaderboardEventReference> LeaderboardEvents;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
	FHyperTwistTrainingLeaderboardDisplayPolicy LeaderboardDisplayPolicy;

	bool IsStructurallyValid() const
	{
		return TaxonomyNodes.Num() > 0
			&& NotationTerms.Num() > 0
			&& ProgressionStages.Num() > 0
			&& SoftwareReferences.Num() > 0
			&& SolverProfiles.Num() > 0
			&& LeaderboardEvents.Num() > 0
			&& LeaderboardDisplayPolicy.IsStructurallyValid();
	}
};

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

public:
	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Knowledge")
	static FHyperTwistTrainingKnowledgeReferenceBundle MakeHypercubingKnowledgeReferenceBundle();

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Knowledge")
	static TArray<FHyperTwistTrainingKnowledgeTaxonomyNode> ListHypercubingTaxonomyNodes();

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Knowledge")
	static TArray<FHyperTwistTrainingNotationReferenceTerm> ListHypercubingNotationTerms();

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Knowledge")
	static TArray<FHyperTwistTrainingProgressionStageReference> ListHypercubingProgressionStages();

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Knowledge")
	static TArray<FHyperTwistTrainingSoftwareReference> ListHypercubingSoftwareReferences();

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Knowledge")
	static TArray<FHyperTwistTrainingLeaderboardSolverProfileReference> ListHypercubingLeaderboardSolverProfiles();

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Knowledge")
	static TArray<FHyperTwistTrainingLeaderboardEventReference> ListHypercubingLeaderboardEvents();

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Knowledge")
	static FHyperTwistTrainingLeaderboardDisplayPolicy GetHypercubingLeaderboardDisplayPolicy();

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Knowledge")
	static bool TryGetHypercubingTaxonomyNode(
		const FString& NodeId,
		FHyperTwistTrainingKnowledgeTaxonomyNode& OutNode
	);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Knowledge")
	static bool TryGetHypercubingNotationTerm(
		const FString& TermId,
		FHyperTwistTrainingNotationReferenceTerm& OutTerm
	);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Knowledge")
	static bool TryGetHypercubingProgressionStage(
		const FString& StageId,
		FHyperTwistTrainingProgressionStageReference& OutStage
	);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Knowledge")
	static bool TryGetHypercubingSoftwareReference(
		const FString& SoftwareId,
		FHyperTwistTrainingSoftwareReference& OutReference
	);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Knowledge")
	static bool TryGetHypercubingLeaderboardEvent(
		const FString& EventId,
		FHyperTwistTrainingLeaderboardEventReference& OutEvent
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Knowledge")
	static FHyperTwistTrainingLeaderboardFormattedValue FormatHypercubingLeaderboardDurationMilliseconds(
		int32 DurationMilliseconds
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Knowledge")
	static FHyperTwistTrainingLeaderboardFormattedValue FormatHypercubingLeaderboardMoveCount(int32 MoveCount);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Knowledge")
	static FString FormatHypercubingLeaderboardRelativeDateLabel(const FString& IsoDate);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Knowledge")
	static FString ResolveHypercubingProgramBadge(const FString& ProgramId);
};
