#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "HyperTwistSimulation/HyperTwistMagic120CellRuntimeLibrary.h"
#include "HyperTwistSimulation/HyperTwistMagicCube5DRuntimeLibrary.h"
#include "HyperTwistHigherDimensionalTrainingShellActor.generated.h"

class UInstancedStaticMeshComponent;
class UMaterialInstanceDynamic;
class UMaterialInterface;
class USceneComponent;
class UStaticMesh;
class UStaticMeshComponent;
class UTextRenderComponent;

UCLASS(BlueprintType)
class UNREALHYPERTWIST_API AHyperTwistHigherDimensionalTrainingShellActor : public AActor
{
	GENERATED_BODY()

public:
	AHyperTwistHigherDimensionalTrainingShellActor();

	virtual void BeginPlay() override;
	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
	virtual void OnConstruction(const FTransform& Transform) override;
	virtual void Tick(float DeltaSeconds) override;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Shell")
	TObjectPtr<USceneComponent> SceneRoot = nullptr;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Shell")
	TObjectPtr<UInstancedStaticMeshComponent> PreviewInstances = nullptr;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Shell")
	TArray<TObjectPtr<UInstancedStaticMeshComponent>> PreviewColorLayers;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Shell")
	TObjectPtr<UStaticMeshComponent> PresentationFloor = nullptr;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Shell")
	TObjectPtr<UTextRenderComponent> LabelComponent = nullptr;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Training|Shell")
	FString FamilyKey = TEXT("magic120cell");

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Training|Shell")
	FString TrainingShellId;

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

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Training|Shell", meta = (MultiLine = "true"))
	FString Summary;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Training|Shell")
	FString MapAssetPath;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Training|Shell")
	FString ActivationProfileId;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Training|Shell")
	FString HostSurfaceId;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Training|Shell")
	FString LaunchSurfaceId;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Training|Shell")
	FString ViewContextSurfaceId;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Training|Shell")
	FString SessionSurfaceId;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Training|Shell")
	FString InteractiveSceneSurfaceId;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Training|Shell")
	FString SceneContextId;

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

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Training|Shell")
	FString RuntimeModeId;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Training|Shell")
	FString ProjectionProfileId;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Training|Shell")
	FString PrimaryPersistenceBoundaryId;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Training|Shell")
	FString AuthoringManifestRelativePath;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Training|Shell")
	bool bDedicatedFamilyOwnership = true;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Training|Shell")
	TArray<FString> TrainingShellTags;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Training|Shell")
	float PreviewRadius = 260.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Training|Shell")
	float PreviewHeightOffset = 90.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Training|Shell|Projection")
	bool bAutoRotateProjection = true;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Training|Shell|Projection", meta = (ClampMin = "0.0"))
	float ProjectionRotationSpeedDegrees = 12.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Training|Shell|Projection", meta = (ClampMin = "0.0"))
	float ProjectionAngleDegrees = 0.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Training|Shell|Projection")
	int32 VisibleProjectionLayer = -1;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Shell|State")
	int32 RuntimeStateSeed = 0;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Shell|State")
	FHyperTwistMagicCube5DRuntimeState MagicCube5DRuntimeState;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Shell|State")
	FHyperTwistMagic120CellRuntimeState Magic120CellRuntimeState;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Shell|State")
	FString LastRuntimeAction = TEXT("ready");

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Shell|Persistence")
	FString LastPersistenceStatus = TEXT("not-loaded");

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Shell")
	void ConfigureForFamily(const FString& InFamilyKey);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Shell|Projection")
	void ToggleAutoRotateProjection();

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Shell|Projection")
	void NudgeProjection(float DeltaDegrees);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Shell|Projection")
	void CycleProjectionLayer(int32 Direction);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Shell|Projection")
	void ResetProjection();

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Shell|State")
	void CreateScrambledRuntimeState();

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Shell|State")
	bool ApplyMagicCube5DTurn(const FHyperTwistMagicCube5DTurnRequest& Request);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Shell|State")
	bool ApplyMagic120CellTurn(const FHyperTwistMagic120CellTurnRequest& Request);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Shell|Persistence")
	bool SaveRuntimeState();

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Shell|Persistence")
	bool LoadRuntimeState();

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Shell")
	int32 GetRenderableElementCount() const;

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Shell")
	int32 GetCanonicalElementCount() const;

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Shell")
	int32 GetProjectionLayerCount() const;

	/** Number of distinct first-party materials assigned to the six projection layers. */
	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Shell|Diagnostics")
	int32 GetDistinctPreviewMaterialCount() const;

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Shell")
	FString GetProjectionLayerLabel() const;

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Shell")
	FString GetRuntimeStatusSummary() const;

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Shell|Persistence")
	FString GetRuntimeStatePath() const;

	static int32 GetCanonicalElementCountForFamily(const FString& InFamilyKey);

private:
	UPROPERTY(Transient)
	TObjectPtr<UStaticMesh> CubePreviewMesh = nullptr;

	UPROPERTY(Transient)
	TObjectPtr<UStaticMesh> SpherePreviewMesh = nullptr;

	UPROPERTY(Transient)
	TArray<TObjectPtr<UMaterialInterface>> PreviewMaterials;

	/** Retained emissive variants prevent GC and preserve layer color on cooked ISM geometry. */
	UPROPERTY(Transient)
	TArray<TObjectPtr<UMaterialInstanceDynamic>> PreviewDynamicMaterials;

	UPROPERTY(Transient)
	TObjectPtr<UMaterialInstanceDynamic> FloorDynamicMaterial = nullptr;

	TArray<FVector4> SourcePoints4D;
	TArray<float> SourceFifthCoordinates;
	TArray<int32> SourceLayerIndices;
	TArray<int32> SourceColorIndices;
	float ProjectionRefreshAccumulator = 0.0f;

	void RefreshPreview();
	void RefreshLabel();
	void RefreshMetadataTags();
	void RebuildSourcePoints();
	void BuildMagic120CellSourcePoints();
	void BuildMagicCube5DSourcePoints();
	void UpdatePreviewTransforms();
	void ClearPreviewInstances();
	void ConfigurePreviewComponents();
	void AddSourcePoint(
		const FVector4& Point4D,
		float FifthCoordinate,
		int32 LayerIndex,
		int32 ColorIndex
	);
	void AddPreviewInstance(
		const FVector& RelativeLocation,
		float UniformScale,
		int32 ColorIndex
	);
	FVector ProjectMagic120CellPoint(const FVector4& Point) const;
	FVector ProjectMagicCube5DPoint(const FVector4& Point, float FifthCoordinate) const;
	FText BuildLabelText() const;
	bool UsesMagic120CellPreview() const;
	FString GetNormalizedFamilyKey() const;
};
