// Copyright Pacificao. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "Subsystems/GameInstanceSubsystem.h"
#include "AgrarianPersistenceSubsystem.generated.h"

class UAgrarianSaveGame;
class UAgrarianPersistentActorComponent;
class AAgrarianGameCharacter;
class AAgrarianResourceNode;

UCLASS()
class UAgrarianPersistenceSubsystem : public UGameInstanceSubsystem
{
	GENERATED_BODY()

public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Persistence")
	FString DefaultSlotName = TEXT("AgrarianMVP");

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Persistence")
	int32 UserIndex = 0;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Persistence")
	TMap<FName, TSubclassOf<AActor>> WorldActorClassRegistry;

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Persistence")
	UAgrarianSaveGame* CreateEmptySave() const;

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Persistence")
	UAgrarianSaveGame* LoadOrCreateSave() const;

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Persistence")
	bool WriteSave(UAgrarianSaveGame* SaveGame) const;

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Persistence")
	bool DoesSaveExist() const;

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Persistence")
	void RegisterWorldActorClass(FName ActorTypeId, TSubclassOf<AActor> ActorClass);

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Persistence")
	int32 CaptureWorldActors(UAgrarianSaveGame* SaveGame) const;

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Persistence")
	int32 RestoreWorldActors(const UAgrarianSaveGame* SaveGame, bool bClearExistingActors = true) const;

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Persistence")
	bool CaptureWorldState(UAgrarianSaveGame* SaveGame) const;

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Persistence")
	bool RestoreWorldState(const UAgrarianSaveGame* SaveGame) const;

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Persistence")
	int32 CapturePlayers(UAgrarianSaveGame* SaveGame) const;

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Persistence")
	int32 RestorePlayers(const UAgrarianSaveGame* SaveGame) const;

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Persistence")
	bool SavePlayerSnapshot(const AAgrarianGameCharacter* Character) const;

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Persistence")
	bool RestorePlayerSnapshot(AAgrarianGameCharacter* Character) const;

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Persistence")
	int32 CaptureResourceNodes(UAgrarianSaveGame* SaveGame) const;

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Persistence")
	int32 RestoreResourceNodes(const UAgrarianSaveGame* SaveGame) const;

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Persistence")
	bool SaveCurrentWorld() const;

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Persistence")
	bool LoadCurrentWorld(int32& RestoredPlayerCount, int32& RestoredWorldActorCount, bool bClearExistingActors = true) const;

protected:
	bool CapturePlayerIntoSave(const AAgrarianGameCharacter* Character, UAgrarianSaveGame* SaveGame) const;
	bool RestorePlayerFromSave(AAgrarianGameCharacter* Character, const UAgrarianSaveGame* SaveGame) const;
	void FindPersistentComponents(TArray<UAgrarianPersistentActorComponent*>& OutComponents) const;
	void FindAgrarianPlayers(TArray<AAgrarianGameCharacter*>& OutPlayers) const;
	void FindResourceNodes(TArray<AAgrarianResourceNode*>& OutResourceNodes) const;
	FString GetPlayerPersistenceId(const AAgrarianGameCharacter* Character) const;
};
