#include "SessionManager.h"
#include "Manager/CsdkSubsystem.h"
#include "Tools/CsdkCommonTools.h"
#include "Message/Tool/MessageTool.h"
#include "Session/CsdkSessionLibrary.h"
#include "Tools/CsdkCommonHttp.h"
#include "Policies/CondensedJsonPrintPolicy.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");

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);
			}
		}
	});
	
	LoadLastReadSeq();

}

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);
}


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

int32 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);
	}
	
}

bool FSessionManager::SaveLastReadSeqToFile()
{
	
	FString JsonStr;
	const TSharedRef<TJsonWriter<TCHAR, TCondensedJsonPrintPolicy<TCHAR>>> JsonWriter =
		TJsonWriterFactory<TCHAR, TCondensedJsonPrintPolicy<TCHAR>>::Create(&JsonStr);
	
	JsonWriter->WriteArrayStart();
	for(const auto& Item: PrivateChatLastReadSequence)
	{
		if(Item.Key.Type != ECsdkSessionType::PrivateChat)
			continue;
		
		JsonWriter->WriteObjectStart();
		JsonWriter->WriteValue(ReceiverIdKey,Item.Key.ReceiverId);
		JsonWriter->WriteValue(ServerIdKey,Item.Key.ServerId);
		JsonWriter->WriteValue(SessionTypeKey,Item.Key.Type);
		JsonWriter->WriteValue(LastReadMsgSeqKey,Item.Value);
		JsonWriter->WriteObjectEnd();
	}
	JsonWriter->WriteArrayEnd();
	JsonWriter->Close();
	return FFileHelper::SaveStringToFile(JsonStr,*GetSavePath());
}

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

	int32 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;
}

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

void FSessionManager::ClearPrivateChatUnreadCount(const FCsdkSessionId& SessionId)
{
	if (const auto& SessionPtr = LocalSessionList.Find(SessionId))
	{
		bool bIsChanged = false;

		if (!SessionPtr->LastMsg) //没有LastMsg，直接返回
		{
			return;
		}
		if (const auto& LastReadSeqPtr = PrivateChatLastReadSequence.Find(SessionId)) //已经有记录了，
		{
			if (*LastReadSeqPtr != SessionPtr->LastMsg->Sequence) //记录不一致，更新记录
			{
				bIsChanged = true;
				*LastReadSeqPtr = SessionPtr->LastMsg->Sequence;
			}
		}
		else //之前无记录
		{
			bIsChanged = true;
			PrivateChatLastReadSequence.Add(SessionId, SessionPtr->LastMsg->Sequence);
		}
		if (bIsChanged)
		{
			CSDK_LOG(LogChatSdk,Log,TEXT("ClearPrivateChatUnreadCount, SessionId:%s,CurrSeq :%d"),*SessionId.ToString(),SessionPtr->LastMsg->Sequence);
			SaveLastReadSeqToFile();
			FCsdkManager::GetInstance().Subsystem->OnSessionUnreadCountChanged.Broadcast(SessionId);
		}
	}
}

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);
	}
}


FString FSessionManager::GetSavePath()
{
	return FPaths::Combine(FCsdkCommonTools::GetUserManager().GetCurrentUserSavePath(),UnReadCountPath+TEXT(".txt"));
}

bool FSessionManager::LoadLastReadSeq()
{
	PrivateChatLastReadSequence.Empty();
	FString JsonStr;
	bool Result = FFileHelper::LoadFileToString(JsonStr, *GetSavePath());
	if(!Result)
	{
		CSDK_LOG(LogChatSdk,Log,TEXT("LoadLastSeq Failed,Load File Failed"));
		return Result;

	}

	TArray<TSharedPtr<FJsonValue>> JsonArray;
	const TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(JsonStr);

	Result =FJsonSerializer::Deserialize(Reader, JsonArray);
	if(!Result)
	{
		CSDK_LOG(LogChatSdk,Error,TEXT("LoadLastSeq Error,Json Deserialize Error"));
		return Result;

	}

	for(const auto& JsonValue: JsonArray)
	{
		const auto& JsonObj = JsonValue->AsObject();
		if(!JsonObj.IsValid())
		{
			continue;
		}
		FCsdkSessionId SessionId;
		SessionId.ReceiverId = JsonObj->GetStringField(ReceiverIdKey);
		SessionId.ServerId = JsonObj->GetStringField(ServerIdKey);
		SessionId.Type = static_cast<ECsdkSessionType::Type>(JsonObj->GetIntegerField(SessionTypeKey));
		int32 LastSeq = JsonObj->GetIntegerField(LastReadMsgSeqKey);
		PrivateChatLastReadSequence.Add(SessionId,LastSeq);
	}
	return true;
}



