#pragma once

#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "HyperTwistReplay/HyperTwistReplayTypes.h"
#include "HyperTwistTraining/HyperTwistTrainingTypes.h"
#include "HyperTwistTrainingLibrary.generated.h"

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

public:
	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
	static FHyperTwistContentPack MakeSampleClassicContentPack();

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
	static bool IsTrainingCaseCompatibleWithPack(
		const FHyperTwistTrainingCase& TrainingCase,
		const FHyperTwistContentPack& ContentPack
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
	static bool CanStartTrainingSession(
		const FHyperTwistTrainingDeck& Deck,
		const FHyperTwistContentPack& ContentPack
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
	static FHyperTwistTrainingSession StartTrainingSession(
		const FHyperTwistTrainingDeck& Deck,
		const FString& UserId,
		const FString& SessionId,
		EHyperTwistTrainingDeliveryMode Mode
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
	static FHyperTwistTrainingRunState StartTrainingRun(
		const FHyperTwistTrainingDeck& Deck,
		const FString& UserId,
		const FString& SessionId,
		EHyperTwistTrainingDeliveryMode Mode
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
	static bool CanTransitionTrainingSession(
		EHyperTwistTrainingSessionState FromState,
		EHyperTwistTrainingSessionState ToState
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
	static FHyperTwistTrainingSession AdvanceTrainingSession(
		const FHyperTwistTrainingSession& Session,
		EHyperTwistTrainingSessionState TargetState,
		const FString& NextCaseId
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
	static FHyperTwistTrainingAdvanceResult AdvanceTrainingSessionWithSelection(
		const FHyperTwistTrainingSession& Session,
		const FHyperTwistTrainingDeck& Deck,
		const TArray<FHyperTwistProgressionMemory>& Memories,
		EHyperTwistTrainingSessionState TargetState
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
	static FHyperTwistTrainingSession RecordTrainingAttempt(
		const FHyperTwistTrainingSession& Session,
		const FHyperTwistTrainingAttempt& Attempt
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
	static FHyperTwistTrainingTimingPolicy NormalizeTimingPolicy(
		const FHyperTwistTrainingTimingPolicy& TimingPolicy
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
	static FHyperTwistTrainingAttempt NormalizeTrainingAttemptTiming(
		const FHyperTwistTrainingAttempt& Attempt,
		const FHyperTwistTrainingTimingPolicy& TimingPolicy
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
	static FHyperTwistTrainingSession CompleteTrainingSession(
		const FHyperTwistTrainingSession& Session,
		bool bAbortSession
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
	static FHyperTwistProgressionMemory MakeInitialProgressionMemory(
		const FHyperTwistTrainingSession& Session,
		const FHyperTwistTrainingCase& TrainingCase
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
	static FHyperTwistProgressionMemory UpdateProgressionMemory(
		const FHyperTwistTrainingSession& Session,
		const FHyperTwistTrainingCase& TrainingCase,
		const FHyperTwistProgressionMemory& CurrentMemory,
		const FHyperTwistTrainingAttempt& Attempt
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
	static FHyperTwistTrainingCaseSelection SelectNextTrainingCase(
		const FHyperTwistTrainingDeck& Deck,
		const TArray<FHyperTwistProgressionMemory>& Memories,
		EHyperTwistTrainingDeliveryMode Mode,
		const FString& CurrentCaseId
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
	static FHyperTwistTrainingSessionSummary DeriveTrainingSessionSummary(
		const FHyperTwistTrainingSession& Session,
      const TArray<FHyperTwistTrainingAttempt>& Attempts,
		const FHyperTwistTrainingImportedRuntimeSelectionState& ImportedRuntimeSelectionState
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
	static FHyperTwistReplayEvent MakeTrainingAttemptReplayEvent(
		const FHyperTwistTrainingSession& Session,
		const FHyperTwistTrainingAttempt& Attempt,
        const FHyperTwistTrainingImportedRuntimeSelectionState& ImportedRuntimeSelectionState,
		int32 TimeMs
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
	static FHyperTwistReplayPacket AppendTrainingAttemptToReplay(
		const FHyperTwistReplayPacket& ReplayPacket,
		const FHyperTwistTrainingSession& Session,
		const FHyperTwistTrainingAttempt& Attempt,
        const FHyperTwistTrainingImportedRuntimeSelectionState& ImportedRuntimeSelectionState,
		int32 TimeMs
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
	static FHyperTwistTrainingAttemptResolution ResolveTrainingAttempt(
		const FHyperTwistTrainingSession& Session,
		const FHyperTwistTrainingDeck& Deck,
		const FHyperTwistTrainingCase& TrainingCase,
		const TArray<FHyperTwistProgressionMemory>& Memories,
		const FHyperTwistTrainingAttempt& Attempt,
        const FHyperTwistTrainingImportedRuntimeSelectionState& ImportedRuntimeSelectionState,
		int32 TimeMs
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
	static FHyperTwistTrainingRunStepResult ResolveTrainingRunAttempt(
		const FHyperTwistTrainingRunState& RunState,
		const FHyperTwistTrainingAttempt& Attempt,
		int32 TimeMs
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
	static FHyperTwistTrainingMethodDrillDefinition BuildMethodDrillDefinitionFromDeck(
		const FHyperTwistTrainingDeck& Deck,
		EHyperTwistTrainingDrillModeKind DrillMode,
		EHyperTwistTrainingDrillVisibilityPolicy VisibilityPolicy,
		bool bAnswerHiddenUntilReveal,
		EHyperTwistTrainingDrillEntrySource EntrySource
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
	static FHyperTwistTrainingMethodDrillRunState StartMethodDrillRun(
		const FHyperTwistTrainingMethodDrillDefinition& DrillDefinition,
		const FString& UserId,
		const FString& RunId
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
	static FHyperTwistTrainingMethodDrillRunState ResumeMethodDrillRunFromBatch(
		const FHyperTwistTrainingMethodDrillDefinition& DrillDefinition,
		const FHyperTwistTrainingMethodDrillBatch& DrillBatch,
		const FString& RunId
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
	static FHyperTwistTrainingMethodDrillRunState StartNextMethodDrillCase(
		const FHyperTwistTrainingMethodDrillRunState& RunState
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
	static FHyperTwistTrainingMethodDrillRunState RevealMethodDrillCase(
		const FHyperTwistTrainingMethodDrillRunState& RunState
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
	static FHyperTwistTrainingMethodDrillRunState RepeatMethodDrillCase(
		const FHyperTwistTrainingMethodDrillRunState& RunState
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
	static FHyperTwistTrainingMethodDrillRunState AdvanceMethodDrillCase(
		const FHyperTwistTrainingMethodDrillRunState& RunState
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
	static FHyperTwistTrainingMethodDrillRunState FinishMethodDrillRun(
		const FHyperTwistTrainingMethodDrillRunState& RunState,
		bool bAbortRun
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
	static FHyperTwistTrainingMethodDrillSummary DeriveMethodDrillSummary(
		const FHyperTwistTrainingMethodDrillRunState& RunState
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
	static FHyperTwistTrainingMethodDrillDiagnosticPacket DeriveMethodDrillDiagnosticPacket(
		const FHyperTwistTrainingMethodDrillRunState& RunState
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
	static FHyperTwistTrainingMethodDrillBatch BuildMethodDrillBatch(
		const FHyperTwistTrainingMethodDrillRunState& RunState,
		const FString& BatchId,
		const FString& Title,
		bool bPinnedFavoritesOnly
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
	static FHyperTwistTrainingDrillCaseModeCompatibility DeriveDrillCaseModeCompatibility(
		const FHyperTwistTrainingCase& TrainingCase,
		EHyperTwistTrainingDrillModeKind DrillMode,
		EHyperTwistTrainingDrillVisibilityPolicy VisibilityPolicy
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
	static TArray<FHyperTwistTrainingCase> FilterDrillCasesByModeCompatibility(
		const TArray<FHyperTwistTrainingCase>& Cases,
		EHyperTwistTrainingDrillModeKind DrillMode,
		EHyperTwistTrainingDrillVisibilityPolicy VisibilityPolicy
	);
};
