git » sdk » main » tree

[main] / borogove / ChatMessageCombiner.hx

package borogove;

using Lambda;

@:expose
class ChatMessageCombiner {
	public static function combine(messages: Array<ChatMessage>): Array<ChatMessage> {
		return messages
			.fold(
				(message, grouped:Map<String, Array<ChatMessage>>) -> {
					final key = correctionKey(message);
					final messages = grouped[key] ?? [];
					grouped.set(key, messages.concat([message]));
					grouped;
				},
				new Map<String, Array<ChatMessage>>()
			)
			.map(messages -> combineMessages(messages));
	}

	private static function correctionKey(message: ChatMessage): String {
		if (message.localId == null) return ID.unique();

		final sender = message.type == MessageCall ? "call" : message.senderId;
		return message.localId + "\n" + message.chatId() + "\n" + sender;
	}

	private static function combineMessages(messages: Array<ChatMessage>): ChatMessage {
		if (messages.length == 1) return messages[0];

		final original = messages.find(message -> message.versions.length == 0) ?? messages[0];
		final combinedVersions = combineVersions(original, messages);
		final newest = combinedVersions[0];

		final builder = ChatMessageBuilder.fromMessage(newest);
		builder.localId = original.localId;
		builder.serverId = original.serverId;
		builder.serverIdBy = original.serverIdBy;
		builder.sortId = original.sortId;
		builder.timeSent = original.timeSent;
		builder.timeReceived = original.timeReceived;
		builder.replyId = original.replyId;
		builder.reactions = original.reactions;
		if (original.type == MessageCall) {
			builder.direction = original.direction;
			builder.senderId = original.senderId;
			builder.from = original.from;
			builder.to = original.to;
			builder.replyTo = original.replyTo.array();
			builder.recipients = original.recipients.array();
		}
		builder.versions = combinedVersions;
		return builder.build();
	}

	private static function combineVersions(
		original: ChatMessage,
		messages: Array<ChatMessage>,
	): Array<ChatMessage> {
		final versions = messages.flatMap(message -> message.versions.array());
		if (original.versions.length == 0) versions.push(original);

		final sortedVersions = versions.fold(
			(version, uniqueVersions:Map<String, ChatMessage>) -> {
				final id = identity(version);
				final previous = uniqueVersions[id];
				if (previous == null || version.timeReceived > previous.timeReceived) {
					uniqueVersions.set(id, version);
				}
				uniqueVersions;
			},
			new Map<String, ChatMessage>()
		).map(version -> version);
		sortedVersions.sort((a, b) -> Reflect.compare(b.timeReceived, a.timeReceived));
		return sortedVersions;
	}

	private static function identity(message: ChatMessage): String {
		return message.serverId == null
			? "local:" + message.localId
			: "server:" + message.serverId + "\n" + message.serverIdBy;
	}
}