#pragma once

// Clean-room implementation for HyperTwist puzzle viewer subsystem — Bound 1
// Lane: cubing/twisty.js (GPL-3.0-or-later — restrictive clean-room lane)
// Implemented from governance docs and abstract idea handoff only.
// No source code inspection. Clean-room workflow only.
// Date: 2026-05-17

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "HyperTwistReplay/HyperTwistReplayTypes.h"
#include "HyperTwistSimulation/HyperTwistSimulationTypes.h"
#include "HyperTwistSimulation/HyperTwistViewerTypes.h"
#include "HyperTwistPuzzleViewerComponent.generated.h"

// ---------------------------------------------------------------------------
// Delegate — broadcast whenever playback state changes
// ---------------------------------------------------------------------------

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(
	FOnViewerPlaybackStateChanged,
	const FHyperTwistViewerPlaybackState&, NewState
);

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(
	FOnViewerPositionSnapshotUpdated,
	const FHyperTwistViewerPositionSnapshot&, NewSnapshot
);

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(
	FOnViewerDirectionStateChanged,
	const FHyperTwistViewerDirectionState&, NewDirectionState
);

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(
	FOnViewerPlaybackJumped,
	const FHyperTwistViewerJumpEvent&, JumpEvent
);

DECLARE_MULTICAST_DELEGATE_OneParam(
	FOnViewerPositionSnapshotUpdatedNative,
	const FHyperTwistViewerPositionSnapshot&
);

DECLARE_MULTICAST_DELEGATE_OneParam(
	FOnViewerDirectionStateChangedNative,
	const FHyperTwistViewerDirectionState&
);

DECLARE_MULTICAST_DELEGATE_OneParam(
	FOnViewerPlaybackJumpedNative,
	const FHyperTwistViewerJumpEvent&
);

// ---------------------------------------------------------------------------
// UHyperTwistPuzzleViewerComponent
//
// Holds a loaded scene context and a flat move list, and manages a pure
// state-machine playback cursor over that list.
//
// Bound 2 adds observer channels and deterministic cursor/timeline transport.
// Bound 3 adds adapter projection and embedded-host bootstrap surfaces.
// Bound 4 adds a visualization shell with local fallback and presentation modes.
// ---------------------------------------------------------------------------

UCLASS(ClassGroup = "HyperTwist", meta = (BlueprintSpawnableComponent), DisplayName = "HyperTwist Puzzle Viewer")
class UNREALHYPERTWIST_API UHyperTwistPuzzleViewerComponent : public UActorComponent
{
	GENERATED_BODY()

public:

	UHyperTwistPuzzleViewerComponent();

	// ------------------------------------------------------------------
	// Load API
	// ------------------------------------------------------------------

	// Load or replace the scene context. Resets playback state.
	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Viewer")
	void LoadSceneContext(const FHyperTwistSimulationSceneContext& InContext);

	// Load or replace the move list. Resets the playhead to the start.
	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Viewer")
	void LoadMoveList(const TArray<FHyperTwistViewerMoveEntry>& InMoveList);

	// Load or replace the replay packet. Derives move-list and replay summary
	// state for the compact shell.
	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Viewer")
	bool LoadReplayPacket(const FHyperTwistReplayPacket& InReplayPacket);

	// ------------------------------------------------------------------
	// Playback control
	// ------------------------------------------------------------------

	// Apply a control request. Advances, retreats, or repositions the playhead.
	// Bound 2: state-machine plus direction/jump observer updates.
	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Viewer")
	void ApplyControlRequest(const FHyperTwistViewerControlRequest& Request);

	// Advance the playing cursor by a deterministic timeline delta.
	// Used by transport automation and host-driven playback without widening
	// into renderer ownership.
	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Viewer")
	bool AdvancePlaybackByMs(int32 DeltaTimeMs);

	// ------------------------------------------------------------------
	// Adapter and host bootstrap
	// ------------------------------------------------------------------

	// Build a deterministic projection packet for a consumer-side classic-cubing
	// viewer adapter without taking classic-cubing ownership into this lane.
	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Viewer")
	bool TryBuildClassicCubingAdapterProjection(FHyperTwistViewerClassicCubingAdapterProjection& OutProjection) const;

	// Prepare a minimal embedded-host bootstrap state from the landed classic-
	// cubing, browser-viewer, and browser-spatial contracts.
	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Viewer")
	bool TryBootstrapEmbeddedClassicCubingHost(
		const FHyperTwistViewerEmbeddedHostBootstrapRequest& Request,
		FHyperTwistViewerEmbeddedHostBootstrapState& OutBootstrapState
	);

	// Build a bounded visualization shell on top of the closed replay, adapter,
	// and browser-support layers without taking browser or classic-cubing
	// ownership into this lane.
	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Viewer")
	bool TryBuildVisualizationShell(
		const FHyperTwistViewerVisualizationShellRequest& Request,
		FHyperTwistViewerVisualizationShellState& OutVisualizationShellState
	);

	// Update only the visualization-local presentation mode for the current
	// shell without widening into host-lifecycle ownership.
	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Viewer")
	bool TrySetVisualizationPresentationMode(
		EHyperTwistViewerPresentationMode NewMode,
		FHyperTwistViewerVisualizationShellState& OutVisualizationShellState
	);

	// ------------------------------------------------------------------
	// Readout accessors
	// ------------------------------------------------------------------

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Viewer")
	FHyperTwistViewerPlaybackState GetPlaybackState() const { return PlaybackState; }

	// Returns the move entry at the current playhead position.
	// Returns a default entry if the move list is empty.
	UFUNCTION(BlueprintPure, Category = "HyperTwist|Viewer")
	FHyperTwistViewerMoveEntry GetCurrentMoveEntry() const;

	// Returns the loaded scene context. Check bSceneContextLoaded before use.
	UFUNCTION(BlueprintPure, Category = "HyperTwist|Viewer")
	FHyperTwistSimulationSceneContext GetSceneContext() const { return SceneContext; }

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Viewer")
	bool HasLoadedReplayPacket() const { return bReplayPacketLoaded; }

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Viewer")
	FHyperTwistDerivedReplaySummary GetReplaySummary() const { return ReplaySummary; }

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Viewer")
	FHyperTwistViewerPositionSnapshot GetPositionSnapshot() const { return PositionSnapshot; }

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Viewer")
	FHyperTwistViewerDirectionState GetDirectionState() const { return DirectionState; }

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Viewer")
	FHyperTwistViewerEmbeddedHostBootstrapState GetHostBootstrapState() const { return HostBootstrapState; }

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Viewer")
	FHyperTwistViewerVisualizationShellState GetVisualizationShellState() const { return VisualizationShellState; }

	// ------------------------------------------------------------------
	// Delegates
	// ------------------------------------------------------------------

	UPROPERTY(BlueprintAssignable, Category = "HyperTwist|Viewer")
	FOnViewerPlaybackStateChanged OnPlaybackStateChanged;

	UPROPERTY(BlueprintAssignable, Category = "HyperTwist|Viewer")
	FOnViewerPositionSnapshotUpdated OnPositionSnapshotUpdated;

	UPROPERTY(BlueprintAssignable, Category = "HyperTwist|Viewer")
	FOnViewerDirectionStateChanged OnDirectionStateChanged;

	UPROPERTY(BlueprintAssignable, Category = "HyperTwist|Viewer")
	FOnViewerPlaybackJumped OnPlaybackJumped;

	FOnViewerPositionSnapshotUpdatedNative OnPositionSnapshotUpdatedNative;
	FOnViewerDirectionStateChangedNative OnDirectionStateChangedNative;
	FOnViewerPlaybackJumpedNative OnPlaybackJumpedNative;

protected:

	virtual void BeginPlay() override;

private:

	UPROPERTY(VisibleAnywhere, Category = "HyperTwist|Viewer")
	FHyperTwistSimulationSceneContext SceneContext;

	UPROPERTY(VisibleAnywhere, Category = "HyperTwist|Viewer")
	TArray<FHyperTwistViewerMoveEntry> MoveList;

	UPROPERTY(VisibleAnywhere, Category = "HyperTwist|Viewer")
	FHyperTwistViewerPlaybackState PlaybackState;

	UPROPERTY(VisibleAnywhere, Category = "HyperTwist|Viewer")
	FHyperTwistViewerPositionSnapshot PositionSnapshot;

	UPROPERTY(VisibleAnywhere, Category = "HyperTwist|Viewer")
	FHyperTwistViewerDirectionState DirectionState;

	UPROPERTY(VisibleAnywhere, Category = "HyperTwist|Viewer")
	FHyperTwistReplayPacket ReplayPacket;

	UPROPERTY(VisibleAnywhere, Category = "HyperTwist|Viewer")
	FHyperTwistDerivedReplaySummary ReplaySummary;

	UPROPERTY(VisibleAnywhere, Category = "HyperTwist|Viewer")
	bool bReplayPacketLoaded = false;

	UPROPERTY(VisibleAnywhere, Category = "HyperTwist|Viewer")
	FHyperTwistViewerEmbeddedHostBootstrapState HostBootstrapState;

	UPROPERTY(VisibleAnywhere, Category = "HyperTwist|Viewer")
	FHyperTwistViewerVisualizationShellState VisualizationShellState;

	UPROPERTY(VisibleAnywhere, Category = "HyperTwist|Viewer")
	TArray<int32> MoveBoundaryTimesMs;

	void RebuildTimelineCache();

	int32 ResolveSeekTargetTimeMs(int32 TargetIndex) const;

	// Rebuild the playback state derived fields and broadcast split observers.
	void RebuildAndBroadcast(
		const FHyperTwistViewerPlaybackState& PreviousPlaybackState,
		const FHyperTwistViewerPositionSnapshot& PreviousPositionSnapshot,
		const FHyperTwistViewerDirectionState& PreviousDirectionState,
		const FHyperTwistViewerJumpEvent* JumpEvent = nullptr
	);
};
