#include "FriendManager.h"
#include "Common/CsdkStringConvert.h"
#include "Log/CsdkLogMacros.h"
#include "relationship/relationship_dto.pb.h"
#include "Tools/CsdkCommonTools.h"
#include "Log/LogChatSdk.h"
#include "Relationship/Friend/Data/CsdkFriendDelResult.h"
#include "Tools/CsdkCommonHttp.h"
#include "User/Tool/UserTool.h"

using namespace heroim::client::v3beta::dto::relationship;


void FFriendManager::Init()
{
	FriendApplyCache.Init();
}

void FFriendManager::Reset()
{
	FriendApplyCache.Clear();
}

void FFriendManager::GetFriendList(const TFunction<void(const int32 ErrorCode, const FString& ErrorMsg, const TArray<FCsdkFriend>& FriendList)>& Callback)
{
	FriendListRequest Request;
	Request.set_allocated_base(FCsdkCommonTools::MakePbBase());

	auto RequestCallBack = [Callback](const int32 ErrorCode,const FString& ErrorMsg,const FriendListResponse& Resp)
	{
		
		CSDK_LOG(LogChatSdk,Log,TEXT("Get FriendList:"));
		TArray<FCsdkFriend> FriendList;
		for(const auto& FriendItem : Resp.list())
		{
			FCsdkFriend Friend;
			Friend.User = CsdkUserTool::ConvertUser(FriendItem.user()); 
			Friend.FriendInfo.BeFriendTime = FriendItem.friend_().friendtime();
			for (const auto& ExtraItem : FriendItem.friend_().extra())
			{
				Friend.FriendInfo.Extra.Add(STD_STRING_TO_FSTRING(ExtraItem.first),STD_STRING_TO_FSTRING(ExtraItem.second));
			}
			CSDK_LOG(LogChatSdk,Log,TEXT("Friend User Info: %s"),*Friend.User.ToString());
			FriendList.Add(Friend);
		}
		Callback(ErrorCode,ErrorMsg,FriendList);
	};
	
	FCsdkCommonHttp<FriendListResponse>::Request(TEXT("/spi/v3beta/rs/friend/list"),Request,RequestCallBack);
}

void FFriendManager::GetFriendApplyList(const TFunction<void(const int32 ErrorCode, const FString& ErrorMsg,const TArray<FCsdkFriendApply>& ApplyList)>& Callback)
{
	FriendApplyCache.GetFriendApplyList(Callback);
}

void FFriendManager::AddFriend(const FCsdkUserId& UserId,const TFunction<void(const int32 ErrorCode, const FString&)>& Callback)
{
	FriendApplyRequest Request;
	Request.set_allocated_base(FCsdkCommonTools::MakePbBase());
	Request.set_allocated_userkey(CsdkUserTool::MakePbUserKey(UserId));
	
	auto RequestCallBack = [Callback](const int32 ErrorCode,const FString& ErrorMsg,const FriendApplyResponse& Resp)
	{
		Callback(ErrorCode,ErrorMsg);
	};
	
	FCsdkCommonHttp<FriendApplyResponse>::Request(TEXT( "/spi/v3beta/rs/friend/apply"),Request,RequestCallBack);
}

void FFriendManager::DeleteFriend(const FCsdkUserId& UserId,const TFunction<void(const int32 ErrorCode, const FString&)>& Callback)
{
	FriendDeleteRequest Request;
	Request.set_allocated_base(FCsdkCommonTools::MakePbBase());
	Request.set_allocated_userkey(CsdkUserTool::MakePbUserKey(UserId));
	
	auto RequestCallBack = [Callback](const int32 ErrorCode,const FString& ErrorMsg,const FriendDeleteResponse& Resp)
	{
		Callback(ErrorCode,ErrorMsg);
	};
	
	FCsdkCommonHttp<FriendDeleteResponse>::Request(TEXT("/spi/v3beta/rs/friend/delete"),Request,RequestCallBack);
}

void FFriendManager::DeleteFriendMulti(const TArray<FCsdkUserId>& UserIds,const TFunction<void(const int32 ErrorCode, const FString&, const TArray<FCsdkFriendDelResult>&)>& Callback)
{
	FriendBatchDeleteRequest Request;
	Request.set_allocated_base(FCsdkCommonTools::MakePbBase());
	for(const auto& UserId:UserIds)
	{
		Request.mutable_userkey()->AddAllocated(CsdkUserTool::MakePbUserKey(UserId));
	}
	
	auto RequestCallBack = [Callback](const int32 ErrorCode,const FString& ErrorMsg,const FriendBatchDeleteResponse& Resp)
	{
		TArray<FCsdkFriendDelResult> DelResults;
		for(const auto& DeleteResItem : Resp.list())
		{
			FCsdkFriendDelResult Result;
			Result.Message = STD_STRING_TO_FSTRING(DeleteResItem.message());
			Result.ErrorCode = DeleteResItem.code();
			Result.UserId = CsdkUserTool::ConvertUserId(DeleteResItem.userkey());
			DelResults.Add(Result);
		}
		Callback(ErrorCode,ErrorMsg, DelResults);
	};
	
	FCsdkCommonHttp<FriendBatchDeleteResponse>::Request(TEXT("/spi/v3beta/rs/friend/batch/delete"),Request,RequestCallBack);
}

void FFriendManager::UpdateFriendInfo(const FCsdkUserId& UserId, const TMap<FString, FString>& UserInfoExtra,
                                      const TFunction<void(const int32 ErrorCode, const FString&)>& Callback)
{
	FriendUpdateRequest Request;
	Request.set_allocated_base(FCsdkCommonTools::MakePbBase());
	Request.set_allocated_userkey(CsdkUserTool::MakePbUserKey(UserId));
	for (const auto& ExtraItem : UserInfoExtra)
	{
		Request.mutable_extra()->insert({FSTRING_TO_STD_STRING(ExtraItem.Key),FSTRING_TO_STD_STRING(ExtraItem.Value)});
	}

	auto RequestCallBack = [Callback](const int32 ErrorCode, const FString& ErrorMsg, const FriendUpdateResponse& Resp)
	{
		Callback(ErrorCode, ErrorMsg);
	};

	FCsdkCommonHttp<FriendUpdateResponse>::Request(TEXT("/spi/v3beta/rs/friend/update"), Request, RequestCallBack);
}

void FFriendManager::AgreeFriendApply(const TArray<FString>& ApplyTokens,
                                      const TFunction<void(const int32 ErrorCode, const FString& ErrorMsg,const TArray<FCsdkOperateFriendApplyResult>& AgreeListResult )>& Callback)
{
	FriendApplyCache.AgreeFriendApply(ApplyTokens,Callback);
}

void FFriendManager::RefuseFriendApply(const TArray<FString>& ApplyTokens,
	const TFunction<void(const int32 ErrorCode, const FString& ErrorMsg, const TArray<FCsdkOperateFriendApplyResult>&
	RefuseListResult)>& Callback)
{
	FriendApplyCache.RefuseFriendApply(ApplyTokens,Callback);
}

void FFriendManager::OnEventReceived(const ERelationshipEventType EventType, const FString& JsonData)
{
	switch (EventType)
	{
	case ERelationshipEventType::FriendApplied:
		OnFriendApplied(JsonData);
		break;
	case ERelationshipEventType::FriendAdded:
		OnFriendAdded(JsonData);
		break;
	case ERelationshipEventType::FriendDeleted:
		OnFriendDeleted(JsonData);
		break;
	default:
		return;
	}
}

int32 FFriendManager::GetUnreadCount()
{
	return FriendApplyCache.GetUnreadCount();
}

void FFriendManager::ClearUnreadCount()
{
	FriendApplyCache.ClearUnreadCount();
}

void FFriendManager::OnFriendApplied(const FString& JsonData)
{
	FriendApplyCache.OnFriendApplied(JsonData);
}

void FFriendManager::OnFriendAdded(const FString& JsonData)
{
	FCsdkUser FromUser, DistUser;
	TSharedPtr<FJsonObject> RootObject = MakeShareable(new FJsonObject());
	const TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(JsonData);
	if (FJsonSerializer::Deserialize(Reader, RootObject))
	{
		const TSharedPtr<FJsonObject>* DataObj = nullptr;
		RootObject->TryGetObjectField(TEXT("fromUser"), DataObj);
		FromUser = CsdkUserTool::ConvertUser(*DataObj);

		RootObject->TryGetObjectField(TEXT("distUser"), DataObj);
		DistUser = CsdkUserTool::ConvertUser(*DataObj);
	}
	//移除好友申请列表的缓存
	if(FromUser.Id != FCsdkCommonTools::GetUserManager().GetCurrentUserId())
	{
		FriendApplyCache.TryRemoveApply(FromUser.Id);
	}
	else if(DistUser.Id != FCsdkCommonTools::GetUserManager().GetCurrentUserId())
	{
		FriendApplyCache.TryRemoveApply(DistUser.Id);
	}

	FCsdkManager::GetInstance().Subsystem->OnFriendAddSuccess.Broadcast(FromUser, DistUser);
	CSDK_LOG(LogChatSdk, Log, TEXT("On Friend Added, From User : %s , Dist User : %s"), *FromUser.ToString(), *DistUser.ToString());
}

void FFriendManager::OnFriendDeleted(const FString& JsonData)
{
	FCsdkUser FromUser;
	TSharedPtr<FJsonObject> RootObject = MakeShareable(new FJsonObject());
	const TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(JsonData);
	if (FJsonSerializer::Deserialize(Reader, RootObject))
	{
		const TSharedPtr<FJsonObject>* DataObj = nullptr;
		RootObject->TryGetObjectField(TEXT("fromUser"), DataObj);
		FromUser = CsdkUserTool::ConvertUser(*DataObj);
	}
	FCsdkManager::GetInstance().Subsystem->OnFriendDeleteSelf.Broadcast(FromUser);
	CSDK_LOG(LogChatSdk,Log,TEXT("On Friend Deleted, User : %s"), *FromUser.ToString());
}
