#pragma once

#include "Online.h"
#include "SessionManager.Generated.h"

/*
	A Class for managing the online subsystem and sessions
*/
UCLASS()
class USessionManager : public UObject
{
	GENERATED_BODY()
	friend class UDefaultGameInstance;
	UPROPERTY()
	class UDefaultGameInstance* m_instance;
public:
	USessionManager();
	void Shutdown();

	void CreateSession(bool destroyOld = true);
	void FindSessions(bool destroyOld = true);
	void JoinSession(const class FOnlineSessionSearchResult& searchResult, bool destroyOld = true);
	void DestroySession();
	void PingResult(const class FOnlineSessionSearchResult& result);

	// Checks if a session is active
	bool SessionExists() const;

	// Mark session as in progress
	void StartSession();
	// Mark session as ended
	void EndSession();

	// Check if we currently are connected to a other clients, client or server
	bool HasNetConnection();

	// Closes all network connections, client or server
	void CloseNetConnections();

	// Routed from the game instance to signal the user has accepted an invite through the online subsystem
	void AcceptUserInvite(const bool bWasSuccess, const int32 ControllerId,
		TSharedPtr<const FUniqueNetId> Us, const FOnlineSessionSearchResult& res);

	// Get a player's nickname for a NetId in the current session
	//UFUNCTION(BlueprintCallable, Category = "Friends")
	FString GetPlayerName(const FUniqueNetId& netID);
	// Get the SteamID of a player or an empty string if not connected to steam
	FString GetSteamID(const FUniqueNetId& netID);
	// Get a player's avatar for a NetId in the current session
	//UFUNCTION(BlueprintCallable, Category="Friends")
	UTexture2D* GetPlayerAvatar(const FUniqueNetId& netID);

	// Public delegates
	DECLARE_MULTICAST_DELEGATE_OneParam(FSessionCallback, bool);
	FSessionCallback onDestroySessionComplete;
	FSessionCallback onCreateSessionComplete;
	FSessionCallback onFindSessionsComplete;
	DECLARE_MULTICAST_DELEGATE_OneParam(FOnJoinSessionComplete, int32);
	FOnJoinSessionComplete onJoinSessionComplete;
	DECLARE_MULTICAST_DELEGATE_TwoParams(FOnAcceptInvite, bool, const FOnlineSessionSearchResult&);
	FOnAcceptInvite onAcceptInvite;
	DECLARE_MULTICAST_DELEGATE_OneParam(FOnPingComplete, bool)
	FOnPingComplete onPingComplete;

	// The settings used when creating new sessions
	FOnlineSessionSettings sessionSettings;
	FOnlineSessionSearchResult joinSessionResult;
	FString joinConnectionString;

	// An ongoing session search
	TSharedPtr<class FOnlineSessionSearch> sessionSearch;

private:
	// Session action callbacks
	void m_OnCreateSessionComplete(FName sessionName, bool successful);
	void m_OnStartOnlineGameComplete(FName sessionName, bool successful);
	void m_OnFindSessionsComplete(bool successful);
	void m_OnJoinSessionComplete(FName sessionName, EOnJoinSessionCompleteResult::Type result);
	void m_OnDestroySessionComplete(FName sessionName, bool successful);
	void m_OnPingSearchResultsComplete(bool successful);

	// Used to create a texture for the player avatars
	class UTexture2D* m_CreateTexture2D(const int32 srcWidth, const int32 srcHeight, const TArray<FColor>& srcColor, const bool useAlpha);

	// Session action callback delegate handles
	FOnCreateSessionCompleteDelegate onCreateSessionCompleteDelegate;
	FOnStartSessionCompleteDelegate onStartSessionCompleteDelegate;
	FOnFindSessionsCompleteDelegate onFindSessionsCompleteDelegate;
	FOnJoinSessionCompleteDelegate onJoinSessionCompleteDelegate;
	FOnDestroySessionCompleteDelegate onDestroySessionCompleteDelegate;
	FOnPingSearchResultsCompleteDelegate onPingSearchResultsCompleteDelegate;
	FDelegateHandle onCreateSessionCompleteDelegateHandle;
	FDelegateHandle onStartSessionCompleteDelegateHandle;
	FDelegateHandle onFindSessionsCompleteDelegateHandle;
	FDelegateHandle onJoinSessionCompleteDelegateHandle;
	FDelegateHandle onDestroySessionCompleteDelegateHandle;
	FDelegateHandle onPingSearchResultsCompleteDelegateHandle;

	// Action to perform after destroy event finished
	int32 m_postDestroyAction;

	// Online subsystem handles
	IOnlineSubsystem* m_onlineSystem;
	IOnlineSessionPtr m_session;

	// The local player's NetId
	TSharedPtr<const FUniqueNetId> m_localNetID;

	// A list of cached profile pictures
	UPROPERTY()
	TMap<FString, UTexture2D*> m_profilePictures;

	// URL for the listen server
	FURL m_listenURL;
};