// Copyright Epic Games, Inc. All Rights Reserved.
// UE5 Modular Game Framework — SS_SaveManager (35)
// Save/Load subsystem. Slot management, serialization, manifest tracking.
// In C++, uses FArchive for direct binary serialization — far more powerful
// than Blueprint "Save Game" / "Load Game" nodes.

#pragma once

#include "CoreMinimal.h"
#include "Subsystems/GameInstanceSubsystem.h"
#include "GameplayTagContainer.h"
#include "SS_SaveManager.generated.h"

/**
 * Save slot metadata returned by GetSlotManifest().
 */
USTRUCT(BlueprintType)
struct PG_FRAMEWORK_API FSaveSlotInfo
{
	GENERATED_BODY()

	UPROPERTY(BlueprintReadOnly)
	int32 SlotIndex = -1;

	UPROPERTY(BlueprintReadOnly)
	FString SlotName;

	UPROPERTY(BlueprintReadOnly)
	FString ChapterName;

	UPROPERTY(BlueprintReadOnly)
	float PlayTimeHours = 0.0f;

	UPROPERTY(BlueprintReadOnly)
	FDateTime Timestamp;

	UPROPERTY(BlueprintReadOnly)
	FGameplayTag LastCheckpoint;

	UPROPERTY(BlueprintReadOnly)
	bool bIsEmpty = true;
};

// Delegates
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnSaveComplete, int32, SlotIndex, bool, bSuccess);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnLoadComplete, int32, SlotIndex, bool, bSuccess);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnSaveManifestUpdated, const TArray<FSaveSlotInfo>&, Slots);

/**
 * SS_SaveManager — Save/Load Subsystem.
 *
 * Manages all save slots, serialization, and manifest tracking.
 * C++ gives us direct FArchive-based serialization, proper error handling,
 * and async save operations — impossible to match in Blueprint.
 */
UCLASS()
class PG_FRAMEWORK_API USS_SaveManager : public UGameInstanceSubsystem
{
	GENERATED_BODY()

public:
	USS_SaveManager();

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

	virtual void Initialize(FSubsystemCollectionBase& Collection) override;
	virtual void Deinitialize() override;

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

	/** Maximum number of save slots. */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Framework|Save")
	int32 MaxSlots = 10;

	/** Save game file prefix for slot naming. */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Framework|Save")
	FString SavePrefix = TEXT("FrameworkSave_");

	// ========================================================================
	// Slot Manifest
	// ========================================================================

	/**
	 * Returns metadata for all save slots.
	 * Fast — reads header only, not full save data.
	 */
	UFUNCTION(BlueprintCallable, Category = "Framework|Save")
	TArray<FSaveSlotInfo> GetSlotManifest() const;

	/**
	 * Checks if a slot has save data.
	 */
	UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Save")
	bool DoesSlotExist(int32 SlotIndex) const;

	// ========================================================================
	// Save / Load Operations
	// ========================================================================

	/**
	 * Save game to a slot. Returns true if successful.
	 * Server-authoritative in multiplayer.
	 */
	UFUNCTION(BlueprintCallable, Category = "Framework|Save")
	bool SaveGame(int32 SlotIndex, const FString& Description);

	/**
	 * Load game from a slot. Returns true if successful.
	 */
	UFUNCTION(BlueprintCallable, Category = "Framework|Save")
	bool LoadGame(int32 SlotIndex);

	/**
	 * Delete a save slot. Irreversible!
	 */
	UFUNCTION(BlueprintCallable, Category = "Framework|Save")
	bool DeleteSlot(int32 SlotIndex);

	/**
	 * Quick-save to the current active slot.
	 */
	UFUNCTION(BlueprintCallable, Category = "Framework|Save")
	bool QuickSave();

	/**
	 * Quick-load from the current active slot.
	 */
	UFUNCTION(BlueprintCallable, Category = "Framework|Save")
	bool QuickLoad();

	// ========================================================================
	// Checkpoint Management
	// ========================================================================

	/** Loads the most recent checkpoint from a slot. */
	UFUNCTION(BlueprintCallable, Category = "Framework|Save")
	bool LoadCheckpoint(int32 SlotIndex);

	/**
	 * Creates a checkpoint within the current slot.
	 * Checkpoints are incremental saves within a single slot.
	 */
	UFUNCTION(BlueprintCallable, Category = "Framework|Save")
	bool CreateCheckpoint(FGameplayTag CheckpointTag);

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

	UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
	FOnSaveComplete OnSaveComplete;

	UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
	FOnLoadComplete OnLoadComplete;

	UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
	FOnSaveManifestUpdated OnSaveManifestUpdated;

	// ========================================================================
	// Utilities
	// ========================================================================

	/** Returns the total disk space used by all saves (in bytes). */
	UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Save")
	int64 GetTotalSaveSize() const;

	/** Backs up all save slots to a Backup/ subdirectory. */
	UFUNCTION(BlueprintCallable, Category = "Framework|Save")
	bool BackupAllSaves(const FString& BackupLabel);

protected:
	/** Builds the save slot name from prefix + index. */
	FString GetSlotName(int32 SlotIndex) const;

	/** Reads only the header/metadata from a save file. */
	FSaveSlotInfo ReadSlotHeader(int32 SlotIndex) const;

	/** Internal save implementation using FArchive serialization. */
	bool SaveToFile(int32 SlotIndex, const TArray<uint8>& Data, const FSaveSlotInfo& Meta);

	/** Internal load implementation. */
	bool LoadFromFile(int32 SlotIndex, TArray<uint8>& OutData, FSaveSlotInfo& OutMeta);

	/** Path to the save directory. */
	FString GetSaveDirectory() const;

	/** Currently active save slot (from GI_GameFramework). */
	int32 GetActiveSlot() const;
};
