#include "MessageManager.h"
#include "Manager/CsdkSubsystem.h"
#include "message/message_dto.pb.h"
#include "message/model/operation.pb.h"
#include "Message/Tool/MessageTool.h"
#include "Message/Tool/PullMsgAutoDeleteTask.h"
#include "Session/Tool/SessionTool.h"
#include "Tools/CsdkCommonHttp.h"
#include "Tools/CsdkCommonTools.h"

using namespace heroim::client::v3beta::dto::message::model;
using namespace heroim::client::v3beta::dto::message;

void FMessageManager::Reset()
{
	for(const auto& Id2Buffer: SessionId2RingBuffer)
	{
		Id2Buffer.Value->Empty();
	}
	SessionId2RingBuffer.Empty();
}


void FMessageManager::SendMsg(const FCsdkSessionId& SessionId, UCsdkMessageBase* CsdkMessage,
                              const TFunction<void(const int32 ErrorCode, const FString& ErrorMsg)>& Callback)
{
	const FString Content =MessageTool::GetContent(CsdkMessage) ;
	
	if(Content.IsEmpty())
	{
		Callback(false,TEXT("Content can't be empty"));
		return;
	}
	MessageSendRequest Request;
	Request.set_allocated_base(FCsdkCommonTools::MakePbBase());
	Request.set_allocated_sessionkey(CsdkSessionTool::MakePbSessionKey(SessionId));
	Request.set_msgtype(MessageTool::ConvertMsgTypeToString(CsdkMessage->MsgType));
	Request.set_content(FSTRING_TO_STD_STRING(Content));
	Request.set_clientmsgid(FSTRING_TO_STD_STRING(CsdkMessage->ClientMsgId));
	
	for(const auto& ExtraItem :CsdkMessage->Extra)
	{
		Request.mutable_payload()->insert({FSTRING_TO_STD_STRING(ExtraItem.Key),FSTRING_TO_STD_STRING(ExtraItem.Value)});
	}
	
	auto RequestCallBack =[Callback](const int32 ErrorCode,const FString& ErrorMsg,const MessageSendResponse& Resp)
	{
		Callback(ErrorCode,ErrorMsg);
	};
	FCsdkCommonHttp<MessageSendResponse>::Request(TEXT("/spi/v3beta/message/send"),Request,RequestCallBack);
}


void FMessageManager::PullMessage(const FCsdkSessionId& SessionId, const FString& AnchorMsgId, const int32 DesiredPullCount,
	const ECsdkMsgPullDirection Direction,
	const TFunction<void(const int32 ErrorCode, const FString& ErrorMsg, const TArray<UCsdkMessageBase*>& Msgs)>& Callback)
{
	
	const auto RingBuffer = GetRingBuffer(SessionId);
	const auto PullTask = new FPullMsgAutoDeleteTask(SessionId,AnchorMsgId,DesiredPullCount,Direction,Callback,RingBuffer);
	PullTask->StartTask();
}

void FMessageManager::MsgNotify(const TArray<uint8>& Data)
{
	if(!FCsdkCommonTools::IsAlive())
		return;
	
	const MessagePackage MsgPackage = TApiResult< MessagePackage>::ParseT(Data);

	FCsdkSessionId SessionId;
	for(const auto& PbMsg : MsgPackage.list())//获取sessionId
	{
		SessionId = CsdkSessionTool::ConvertSessionId(PbMsg.sessionkey());
		
		break;
	}
	
	if(!SessionId2RingBuffer.Contains(SessionId)) //找不到缓存且添加缓存
	{
		SessionId2RingBuffer.Add(SessionId,MakeShareable(new FCsdkMessageRingBuffer{SessionId}));
	}

	const auto RingBuffer = *SessionId2RingBuffer.Find(SessionId);
	
	TArray<UCsdkMessageBase*> NewMsgs;
	for(const auto& PbMsg : MsgPackage.list())
	{
		if(RingBuffer->Contains(STD_STRING_TO_FSTRING(PbMsg.msgid())))//如果缓存中已经有此条消息，与获取历史消息冲突，跳过此消息
		{
			continue;
		}
		//创建新的消息体
		const auto NewMsg = MessageTool::NewMsgObj(FCsdkManager::GetInstance().Subsystem,PbMsg);
		RingBuffer->PushBack(NewMsg);
		//判断消息是否有拉黑
		if(!FCsdkCommonTools::GetBlockManager().IsUserIdBlocked(NewMsg->Sender.Id))
		{
			NewMsgs.Add(NewMsg);
		}
	}
	if(NewMsgs.Num()>0)
	{
		
		//广播会话变更
		FCsdkCommonTools::GetSessionManager().CreateOrUpdateSession(SessionId,NewMsgs.Last());

	
		//广播收到新消息
		FCsdkManager::GetInstance().Subsystem->OnNewMessagesReceived.Broadcast(SessionId,NewMsgs);
		
		if(NewMsgs.Last()->Sender.Id != FCsdkCommonTools::GetUserManager().GetCurrentUserId())
		{
			if(SessionId.Type !=ECsdkSessionType::PrivateChat )
			{
				FCsdkCommonTools::GetSessionManager().AddNotPrivateChatUnreadCount(SessionId,NewMsgs.Num());
			}
			//会话未读数变更
			FCsdkManager::GetInstance().Subsystem->OnSessionUnreadCountChanged.Broadcast(SessionId);
		}
		
	}

	
}

void FMessageManager::OnEventReceived(const EMessageEventType EventType, const FString& JsonData)
{
	if (EventType == EMessageEventType::ClearSessionMsg)
	{
		TSharedRef<TJsonReader<>> JsonReader = TJsonReaderFactory<TCHAR>::Create(JsonData);
		TSharedPtr<FJsonObject> JsonObject;
		// 反序列化，将JsonReader里面的数据，传到JsonObject中
		if(FJsonSerializer::Deserialize(JsonReader, JsonObject))
		{
			FCsdkSessionId SessionId;
			SessionId.Type =static_cast<ECsdkSessionType::Type>(JsonObject->GetIntegerField(TEXT("sessionType")));
			auto group = JsonObject->GetObjectField(TEXT("group"));
			SessionId.ReceiverId = group->GetStringField(TEXT("customId"));
			SessionId.ServerId = group->GetStringField(TEXT("serverId"));
			SessionId2RingBuffer[SessionId]->Empty();
			FCsdkManager::GetInstance().Subsystem->OnClearSessionMsg.Broadcast(SessionId);
		}
	}
}


TSharedPtr<FCsdkMessageRingBuffer> FMessageManager::GetRingBuffer(const FCsdkSessionId& SessionId)
{
	if(!SessionId2RingBuffer.Contains(SessionId)) //找不到缓存且添加缓存
	{
		SessionId2RingBuffer.Add(SessionId,MakeShareable(new FCsdkMessageRingBuffer{SessionId}));
	}
	
	return *SessionId2RingBuffer.Find(SessionId);
}



