#include "SessionManager.h"
#include "Manager/CsdkSubsystem.h"
#include "message/session_dto.pb.h"
#include "Tools/CsdkCommonTools.h"
#include "Message/Tool/MessageTool.h"
#include "Session/CsdkSessionLibrary.h"
#include "Tools/CsdkCommonHttp.h"
#include "Policies/CondensedJsonPrintPolicy.h"
#include "Session/Tool/SessionTool.h"

const FString FSessionManager::UnReadCountPath =TEXT("SessionUnReadCount");

const FString FSessionManager::ReceiverIdKey = TEXT("ReceiverId");
const FString FSessionManager::ServerIdKey = TEXT("ServerId");
const FString FSessionManager::SessionTypeKey = TEXT("SessionType");
const FString FSessionManager::LastReadMsgSeqKey = TEXT("LastReadMsgSeq");

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

void FSessionManager::Init()
{
	LocalSessionList.Initialize([this](const int32 ErrorCode,const FString& ErrorMsg,TArray<UCsdkSession*> Sessions)
	{
		for(const auto& Session: Sessions)
		{
			if( GetUnreadCount(Session->SessionId) !=0)
			{
				FCsdkManager::GetInstance().Subsystem->OnSessionUnreadCountChanged.Broadcast(Session->SessionId);
			}
		}
	});

}

void FSessionManager::Reset()
{
	LocalSessionList.Empty();
	PrivateChatLastReadSequence.Empty();
	NotPrivateChatId2UnreadCount.Empty();
}

UCsdkSession* FSessionManager::GetSessionById(const FCsdkSessionId& SessionId) const
{
	if(const auto Session =LocalSessionList.Find(SessionId))
	{
		return Session;
	}
	 return nullptr;
}

UCsdkSession* FSessionManager::CreateOrUpdateSession(const FCsdkSessionId& SessionId, UCsdkMessageBase* LastMsg)
{
	auto Session = LocalSessionList.Find(SessionId);
	if(!Session)
	{
		Session = NewObject<UCsdkSession>(FCsdkManager::GetInstance().Subsystem);
		Session->SessionId = SessionId;
		if(LastMsg)
		{
			Session->UpdateTime = LastMsg->Time;
			Session->LastMsg = LastMsg;
		}
		else
		{
			Session->UpdateTime = FDateTime::UtcNow();
		}
		LocalSessionList.Add(Session);
		LocalSessionList.Sort();
		FCsdkManager::GetInstance().Subsystem->OnSessionChanged.Broadcast(ECsdkSessionChanged::SessionCreate, Session);
		return Session;
	}
	
	if(LastMsg)
	{
		Session->UpdateTime = LastMsg->Time;
		Session->LastMsg = LastMsg;
		LocalSessionList.Sort();
		FCsdkManager::GetInstance().Subsystem->OnSessionChanged.Broadcast(ECsdkSessionChanged::SessionUpdate, Session);
	}
	return Session;
}

UCsdkSession* FSessionManager::FindSession(const FCsdkSessionId& SessionId) const
{
	const auto Session = LocalSessionList.Find(SessionId);
	if(!Session)
	{
		return nullptr;
	}
	return Session;
}

void FSessionManager::DeleteSession(const FCsdkSessionId& SessionId,
                                    const TFunction<void(const int32 ErrorCode, const FString& ErrorMsg)>& Callback)
{
	LocalSessionList.DeleteSession(SessionId,Callback);
}

void FSessionManager::RemoveLocalSession(const FCsdkSessionId& SessionId)
{
	LocalSessionList.RemoveLocalSession(SessionId);
}

void FSessionManager::GetSessionList(TFunction<void(const int32 ErrorCode,const FString& ErrorMsg,TArray<UCsdkSession*>)> Callback)
{
	LocalSessionList.GetSessionList(Callback);
}

void FSessionManager::PinSession(const FCsdkSessionId& SessionId,const	bool bIsPinned,
	const TFunction<void(const int32 ErrorCode, const FString& ErrorMsg, const FDateTime& PinnedTime)>& Callback)
{
	LocalSessionList.PinSession(SessionId,bIsPinned,Callback);
}


int64 FSessionManager::GetUnreadCount(const FCsdkSessionId& SessionId)
{
	if(SessionId.Type == ECsdkSessionType::PrivateChat)
	{
		return GetPrivateChatUnreadCount(SessionId);
	}
	return GetNotPrivateChatUnreadCount(SessionId);
}

int64 FSessionManager::GetAllUnreadCount()
{
	int32 Result = 0;
	for(const auto& SessionPtr :LocalSessionList)
	{
		Result += GetUnreadCount(SessionPtr->SessionId);
	}
	return Result;
}

void FSessionManager::ClearUnreadCount(const FCsdkSessionId& SessionId)
{
	CSDK_LOG(LogChatSdk,Log,TEXT("SessionId:%s call ClearUnreadCount"),*SessionId.ToString());
	if(SessionId.Type == ECsdkSessionType::PrivateChat)
	{
		return ClearPrivateChatUnreadCount(SessionId);
	}
	return ClearNotPrivateChatUnreadUnreadCount(SessionId);
	
}

void FSessionManager::AddNotPrivateChatUnreadCount(const FCsdkSessionId& SessionId, int32 IncreaseCount)
{
	checkf(SessionId.Type != ECsdkSessionType::PrivateChat,TEXT("SessionType can't be PrivateChat"))
	
	if(NotPrivateChatId2UnreadCount.Contains(SessionId))
	{
		NotPrivateChatId2UnreadCount[SessionId] = NotPrivateChatId2UnreadCount[SessionId]+IncreaseCount;
	}
	else
	{
		NotPrivateChatId2UnreadCount.Add(SessionId,IncreaseCount);
	}
	
}

void FSessionManager::UpdatePrivateChatSequence(const FCsdkSessionId& SessionId, int64 Sequence)
{
	auto CurReadSeq = PrivateChatLastReadSequence.Find(SessionId);
	if (!CurReadSeq || *CurReadSeq < Sequence)
	{
		PrivateChatLastReadSequence.Emplace(SessionId,Sequence);
	}
		
}


void FSessionManager::InitPrivateChatSequence(const FCsdkSessionId& SessionId, int64 LastSequence, int64 ReadSequence)
{
	PrivateChatLastReadSequence.Emplace(SessionId,ReadSequence);
	PrivateChatInitLastSequence.Emplace(SessionId,LastSequence);
}

int64 FSessionManager::GetPrivateChatUnreadCount(const FCsdkSessionId& SessionId)
{
	int64 CurrentSeq = 0;
	const auto SessionPtr = LocalSessionList.Find(SessionId);
	if (SessionPtr && SessionPtr->LastMsg ) //能找到当前会话
	{
		if (SessionPtr->LastMsg->bIsSelf) //最后一条消息是自己发的，不计入未读数
		{
			CurrentSeq = SessionPtr->LastMsg->Sequence - 1;
		}
		else
		{
			CurrentSeq = SessionPtr->LastMsg->Sequence;
		}
	}
	else if (const auto InitSequencePtr = PrivateChatInitLastSequence.Find(SessionId))
	{
		CurrentSeq = *InitSequencePtr;
	}
	else
	{
		CSDK_LOG(LogChatSdk, Error, TEXT("GetUnreadCount:Can't Find SessionId, , SessionId:%s,CurrentSeq:%d"), *SessionId.ToString(),
		         CurrentSeq);
		return 0;
	}

	int64 LastReadSeq = 0;
	if (const auto& LastReadSeqPtr = PrivateChatLastReadSequence.Find(SessionId)) //能在缓存中找到已读数据
	{
		LastReadSeq = *LastReadSeqPtr;
	}
	else
	{
		LastReadSeq = 0;
		PrivateChatLastReadSequence.Add(SessionId, LastReadSeq);
	}
	const int32 UnreadCount = CurrentSeq - LastReadSeq < 0 ? 0 : CurrentSeq - LastReadSeq; //未读数必须大于0
	CSDK_LOG(LogChatSdk, Log, TEXT("GetUnreadCount: SessionId:%s,CurrentSeq:%d,LastReadSeq:%d,UnreadCount:%d"),
	         *SessionId.ToString(), CurrentSeq, LastReadSeq, UnreadCount);
	return UnreadCount;
}

int64 FSessionManager::GetNotPrivateChatUnreadCount(const FCsdkSessionId& SessionId)
{
	if (const auto& UnreadPtr = NotPrivateChatId2UnreadCount.Find(SessionId)) //能找到当前会话
	{
		const int64 Result = *UnreadPtr;
		return Result;
	}
	return 0;
}

void FSessionManager::ClearPrivateChatUnreadCount(const FCsdkSessionId& SessionId)
{
	if (const auto& SessionPtr = LocalSessionList.Find(SessionId))
	{
		if (!SessionPtr->LastMsg) //没有LastMsg，直接返回
		{
			return;
		}
		
		const auto LastReadSeqPtr = PrivateChatLastReadSequence.Find(SessionId);
		if ( LastReadSeqPtr && *LastReadSeqPtr >= SessionPtr->LastMsg->Sequence) //已经有记录了，
		{
			return;
		}
		
		PrivateChatLastReadSequence.Emplace(SessionId, SessionPtr->LastMsg->Sequence);
		FCsdkManager::GetInstance().Subsystem->OnSessionUnreadCountChanged.Broadcast(SessionId);

		
		auto RequestCallBack = [this,SessionId,SequenceId = SessionPtr->LastMsg->Sequence](const int32 ErrorCode, const FString& ErrorMsg,
										   const SessionReadResponse& Resp)
		{
			CSDK_LOG(LogChatSdk,Log,TEXT("ClearPrivateChatUnreadCount, SessionId:%s,SeqId :%d"),*SessionId.ToString(),SequenceId);
		};
		
		SessionReadRequest Request;
		Request.set_allocated_base(FCsdkCommonTools::MakePbBase());
		Request.set_allocated_sessionkey(CsdkSessionTool::MakePbSessionKey(SessionId));
		Request.set_seq(SessionPtr->LastMsg->Sequence);
		FCsdkCommonHttp<SessionReadResponse>::Request(TEXT("/spi/v3beta/message/session/read"), Request, RequestCallBack);
	}
}

void FSessionManager::ClearNotPrivateChatUnreadUnreadCount(const FCsdkSessionId& SessionId)
{
	if (NotPrivateChatId2UnreadCount.Contains(SessionId)) //已经有记录了，
	{
		if(NotPrivateChatId2UnreadCount[SessionId]!=0)
		{
			NotPrivateChatId2UnreadCount[SessionId] =0;
			CSDK_LOG(LogChatSdk,Log,TEXT("ClearNotPrivateChatUnreadUnreadCount, SessionId:%s,Unread Count 0 "),*SessionId.ToString());
			FCsdkManager::GetInstance().Subsystem->OnSessionUnreadCountChanged.Broadcast(SessionId);
		}
	}
	else
	{
		NotPrivateChatId2UnreadCount.Add(SessionId,0);
	}
}





