// Copyright Epic Games, Inc. All Rights Reserved.
// UE5 Modular Game Framework — GI_GameFramework (04)
// Application kernel GameInstance. Owns all SS_ subsystems, manages game phases,
// platform initialization, save slot ownership, and service resolution.

#pragma once

#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "GameplayTagContainer.h"
#include "GI_GameFramework.generated.h"

// Forward declarations
class UDA_GameTagRegistry;
class USS_SaveManager;
class USS_UIManager;
class USS_SettingsSystem;
class USS_EnhancedInputManager;
class USS_AchievementSystem;
class USS_AudioManager;

/**
 * Game Phase — top-level application state.
 * Transitions are server-authoritative; clients receive via OnRep_GamePhase.
 */
UENUM(BlueprintType)
enum class EGamePhase : uint8
{
	MainMenu     UMETA(DisplayName = "Main Menu"),
	Loading      UMETA(DisplayName = "Loading"),
	InGame       UMETA(DisplayName = "In Game"),
	Paused       UMETA(DisplayName = "Paused"),
	Cutscene     UMETA(DisplayName = "Cutscene"),
	DeathLoop    UMETA(DisplayName = "Death Loop"),
	AltDeathSpace UMETA(DisplayName = "Alt Death Space"),
	Credits      UMETA(DisplayName = "Credits"),
	PostGame     UMETA(DisplayName = "Post Game"),
};

/** Platform type for platform-specific initialization routing. */
UENUM(BlueprintType)
enum class EPlatformType : uint8
{
	Generic UMETA(DisplayName = "Generic (PC)"),
	Steam   UMETA(DisplayName = "Steam"),
	PS5     UMETA(DisplayName = "PlayStation 5"),
	Xbox    UMETA(DisplayName = "Xbox Series X|S"),
	Switch  UMETA(DisplayName = "Nintendo Switch"),
};

// ============================================================================
// Delegates (Event Dispatchers)
// ============================================================================

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnGamePhaseChanged, EGamePhase, NewPhase);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnPlatformReady);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnFrameworkReady);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnFrameworkInitFailed, const FString&, ErrorReason);

/**
 * GI_GameFramework — Application Kernel.
 *
 * The single persistent object that lives for the entire application session.
 * Owns all SS_ GameInstanceSubsystems, manages save slot ownership, provides
 * the canonical service resolver (GetService()), and tracks the top-level
 * game phase state machine.
 *
 * In C++, this replaces the Blueprint "Get Game Instance → Cast → Get Subsystem"
 * pattern with clean template access via GetService<T>().
 */
UCLASS(Blueprintable)
class PG_FRAMEWORK_API UGI_GameFramework : public UGameInstance
{
	GENERATED_BODY()

public:
	UGI_GameFramework();

	// ========================================================================
	// Lifecycle
	// ========================================================================

	virtual void Init() override;
	virtual void Shutdown() override;

	// ========================================================================
	// Configuration
	// ========================================================================

	/** Hard reference to the tag registry Data Asset. Loaded during Init. */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Framework|Config")
	TObjectPtr<UDA_GameTagRegistry> TagRegistry;

	/** If true, validates all tags during Init. Recommended: true for development. */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Framework|Config")
	bool bValidateTagsOnInit = true;

	/** If true, logs all registered tags to the output log during Init. */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Framework|Debug")
	bool bLogTagsOnInit = false;

	/** Platform override. Determined automatically; can be overridden via command-line: -Platform=Steam */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Framework|Platform")
	EPlatformType PlatformType = EPlatformType::Generic;

	// ========================================================================
	// Game Phase State Machine
	// ========================================================================

	/** Current top-level game phase. Server-authoritative; replicated to clients. */
	UPROPERTY(BlueprintReadOnly, Category = "Framework|State")
	EGamePhase CurrentGamePhase = EGamePhase::MainMenu;

	/**
	 * Sets the game phase and broadcasts OnGamePhaseChanged.
	 * Server-authoritative. No-ops if phase is unchanged.
	 */
	UFUNCTION(BlueprintCallable, Category = "Framework|State")
	void SetGamePhase(EGamePhase NewPhase);

	/** Returns whether the framework has completed initialization. */
	UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|State")
	bool IsFrameworkReady() const { return bFrameworkInitialized; }

	// ========================================================================
	// Session Flags (Transient, Non-Persisted)
	// ========================================================================

	/** Gets a session flag value. Returns false if the flag doesn't exist. */
	UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Session")
	bool GetSessionFlag(FGameplayTag FlagTag) const;

	/** Sets a session flag. Creates it if it doesn't exist. */
	UFUNCTION(BlueprintCallable, Category = "Framework|Session")
	void SetSessionFlag(FGameplayTag FlagTag, bool bValue);

	/** Clears all session flags. Called on new game start. */
	UFUNCTION(BlueprintCallable, Category = "Framework|Session")
	void ClearAllSessionFlags();

	// ========================================================================
	// Save Slot Management
	// ========================================================================

	/** Currently active save slot index (-1 = none). */
	UPROPERTY(BlueprintReadOnly, Category = "Framework|Save")
	int32 ActiveSlotIndex = -1;

	/** Designates the active save slot. Does NOT trigger a load. */
	UFUNCTION(BlueprintCallable, Category = "Framework|Save")
	void SetActiveSlot(int32 SlotIndex);

	// ========================================================================
	// Service Resolution
	// ========================================================================

	/**
	 * Canonical subsystem accessor. Maps a GameplayTag to a subsystem class.
	 * Returns nullptr and logs warning if tag isn't mapped or subsystem unavailable.
	 */
	UFUNCTION(BlueprintCallable, Category = "Framework|Services")
	UGameInstanceSubsystem* GetService(FGameplayTag ServiceTag) const;

	/** Template accessor for type-safe subsystem retrieval. */
	template<typename T>
	T* GetService() const
	{
		return GetSubsystem<T>();
	}

	// ========================================================================
	// First-Launch State
	// ========================================================================

	/** True until onboarding/intro sequence clears it. */
	UPROPERTY(BlueprintReadOnly, Category = "Framework|State")
	bool bFirstLaunch = true;

	// ========================================================================
	// Event Dispatchers
	// ========================================================================

	/** Broadcast when game phase changes. All systems react to this — never poll CurrentGamePhase. */
	UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
	FOnGamePhaseChanged OnGamePhaseChanged;

	/** Broadcast when platform-specific initialization is complete. */
	UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
	FOnPlatformReady OnPlatformReady;

	/** Broadcast when framework initialization is complete and tag registry is validated. */
	UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
	FOnFrameworkReady OnFrameworkReady;

	/** Broadcast if framework initialization fails (missing tag registry, zero tags, etc.). */
	UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
	FOnFrameworkInitFailed OnFrameworkInitFailed;

protected:
	// ========================================================================
	// Internal State
	// ========================================================================

	bool bFrameworkInitialized = false;

	/** Map of GameplayTag → bool for session-scoped flags. */
	UPROPERTY()
	TMap<FGameplayTag, bool> SessionFlags;

	/** Maps service GameplayTags to subsystem classes. Populated during Init. */
	UPROPERTY()
	TMap<FGameplayTag, TSubclassOf<UGameInstanceSubsystem>> ServiceRegistry;

	// ========================================================================
	// Internal Methods
	// ========================================================================

	/** Platform-specific initialization routing. */
	void InitPlatformServices();

	/** Validates the tag registry and logs results. */
	void ValidateFrameworkTags();

	/** Builds the ServiceRegistry map of GameplayTag → SubsystemClass. */
	void RegisterServices();
};
