#pragma once

#include "client/v3beta/dto/shared/api.pb.h"
#include "Common/CsdkPlatform.h"
#include "Common/CsdkStringConvert.h"
#include "herogoogle/protobuf/util/json_util.h"
#include "Interfaces/IHttpRequest.h"
#include "Manager/CsdkManager.h"
#include "Message/Core/MessageManager.h"
#include "Misc/Paths.h"

class FCsdkCommonTools
{
public:
	constexpr static ECsdkPlatform GetPlatform()
	{
		{
#if PLATFORM_IOS
		 	return ECsdkPlatform::IOS;
#elif PLATFORM_ANDROID
		 	return ECsdkPlatform::Android;
#elif PLATFORM_WINDOWS
			return ECsdkPlatform::Windows;
#else
		 	return ECsdkPlatform::None;
#endif
		}
	}
	
	FORCEINLINE static FSystemSetting& GetSystemSetting()
	{
		return  FCsdkManager::GetInstance().InitManager.SystemSetting;
	}

	FORCEINLINE static FInitManager& GetInitManager()
	{
		return   FCsdkManager::GetInstance().InitManager;
	}
	
	FORCEINLINE static FLoginManager& GetLoginManager()
	{
		return   FCsdkManager::GetInstance().LoginManager;
	}
	
	FORCEINLINE static FUserManager& GetUserManager()
	{
		return   FCsdkManager::GetInstance().UserManager;
	}
	
	FORCEINLINE static FFriendManager& GetFriendManager()
	{
		return   FCsdkManager::GetInstance().FriendManager;
	}

	FORCEINLINE static FBlockManager& GetBlockManager()
	{
		return   FCsdkManager::GetInstance().BlockManager;
	}

	FORCEINLINE static FMessageManager& GetMessageManager()
	{
		return   FCsdkManager::GetInstance().MessageManager;
	}

	FORCEINLINE static FSessionManager& GetSessionManager()
	{
		return   FCsdkManager::GetInstance().SessionManager;
	}

	FORCEINLINE static FChatRoomManager& GetChatRoomManager()
	{
		return FCsdkManager::GetInstance().ChatRoomManager;
	}

	FORCEINLINE static FTranslateManager& GetTranslateManager()
	{
		return FCsdkManager::GetInstance().TranslateManager;
	}

	FORCEINLINE static FConsensusManager& GetConsensusManager()
	{
		return FCsdkManager::GetInstance().ConsensusManager;
	}
	
	static TArray<uint8> ConvertPbStructToBytes(const herogoogle::protobuf::MessageLite& MsgLite)
	{
		TArray<uint8> Buffer;
		Buffer.SetNum(MsgLite.ByteSizeLong());
		MsgLite.SerializeToArray(Buffer.GetData(),Buffer.Num());
		return Buffer;
	}

	static TArray<uint8> ConvertPbStructToBytes(const TSharedPtr<::herogoogle::protobuf::MessageLite>& MsgLite)
	{
		TArray<uint8> Buffer;
		Buffer.SetNum(MsgLite->ByteSizeLong());
		MsgLite->SerializeToArray(Buffer.GetData(),Buffer.Num());
		return Buffer;
	}
	
	FORCEINLINE static bool IsInit()
	{
		return FCsdkManager::GetInstance().InitManager.bIsInit;
	}
	
	
	FORCEINLINE static const FString& GetHttpAddress()
	{
		return GetSystemSetting().HttpAddress;
	}

	FORCEINLINE static const FString& GetProductId()
	{
		return GetSystemSetting().ProductId;
	}

	FORCEINLINE static const FString& GetProductKey()
	{
		return GetSystemSetting().ProductKey;
	}
	
	FORCEINLINE static const FString& GetWsAddress()
	{
		return GetSystemSetting().WsAddress;
	}
	
	FORCEINLINE static  bool HasLogin()
	{
		return FCsdkManager::GetInstance().LoginManager.bHasLogin;
	}

	FORCEINLINE static  FString GetToken()
	{
		return FCsdkManager::GetInstance().LoginManager.Token;
	}
	
	FORCEINLINE static FString GetSeverId()
	{
		return GetUserManager().GetCurrentUserId().ServerId;
	}

	FORCEINLINE static bool IsAlive()
	{
		return FCsdkManager::GetInstance().bIsAlive;
	}
	
	static void HttpV2SetDefaultHeader(const TSharedRef<IHttpRequest, ESPMode::ThreadSafe> HttpRequest)
	{
		HttpRequest->SetHeader(TEXT("Content-Type"), TEXT("application/x-protobuf"));
		HttpRequest->SetHeader(TEXT("Accept"), TEXT("application/x-protobuf"));
		HttpRequest->SetHeader(TEXT("productId"),GetSystemSetting().ProductId);
	
		const FString Nonce =FGuid::NewGuid().ToString();
		HttpRequest->SetHeader(TEXT("nonce"),*Nonce);
	
		const FDateTime Time = FDateTime::UtcNow();
		const int64 TimeStamp =Time.ToUnixTimestamp()*1000;
		HttpRequest->SetHeader(TEXT("timestamp"),FString::Printf(TEXT("%lld"),TimeStamp));
	
		const FString SignMid =FString::Printf(TEXT("nonce=%s&productId=%s&timestamp=%lld&%s"),*Nonce,
											   *GetSystemSetting().ProductId,TimeStamp,
											   *GetSystemSetting().ProductKey);
		const FString Sign =FMD5::HashAnsiString(*SignMid);
		HttpRequest->SetHeader(TEXT("sign"),*Sign);
		const FString ApiToken = GetToken();
		HttpRequest->SetHeader(TEXT("apiToken"), ApiToken);
	}

	FORCEINLINE static heroim::client::v3beta::dto::shared::APIRequest* MakePbBase()
	{
		auto* PbBasePtr = new heroim::client::v3beta::dto::shared::APIRequest;
		PbBasePtr->set_productid(FSTRING_TO_STD_STRING(GetProductId()));
		const FString UserId = FCsdkCommonTools::GetUserManager().GetCurrentUser().ToString();
		const FString DeviceId = FCsdkManager::GetInstance().GetDeviceId() + "_" + UserId + "_Hardware:"+ FPlatformMisc::GetDeviceId();
		PbBasePtr->set_deviceid(FSTRING_TO_STD_STRING(DeviceId));
		const FString Version = FString::Printf(TEXT("%d.%d.%d"),CSDK_MajorVersion,CSDK_MiddleVersion,CSDK_MinorVersion);
		PbBasePtr->set_clientsdkversion(FSTRING_TO_STD_STRING(Version));
		return  PbBasePtr;
	}

	FORCEINLINE static FString CSdkSaveDir()
	{
		return FPaths::Combine(FPaths::ProjectSavedDir(),TEXT("Csdk"));
	}


	FORCEINLINE static FString ParsePbToJson(const ::herogoogle::protobuf::Message& Message)
	{
		std::string RequestStr;
		herogoogle::protobuf::util::JsonPrintOptions Options;
		Options.always_print_primitive_fields = true;
		Options.preserve_proto_field_names = true;
		MessageToJsonString(Message,&RequestStr,Options);
		return STD_STRING_TO_FSTRING(RequestStr);
	}
};

