Збірка усіх плаґінів для WhoMine розроблених [MinersStudios](https://minersstudios.github.io).
// https://github.com/MinersStudios/msUtils/discussions/18#discussioncomment-6272771

package ua.com.minersstudios.whomine.util.misc;
import java.text.MessageFormat;
import lombok.*;
import lombok.experimental.UtilityClass;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;

@UtilityClass
public class IngameChatMessageFactory
{
	public enum Chat {GLOBAL, LOCAL}
	public enum RolePlayActionType {DO, IT, ME, TODO}

	/**
	 * Send message to the game chat.
	 * @param playerInfo	PlayerInfo object
	 * @param location		sender's location
	 * @param chat			chat to use
	 * @param message		message to be sent
	 * @deprecated
	 */
	// TODO: Will be replaced when new API comes out.
	@Deprecated
	public void sendMessageToChat(
		@NonNull PlayerInfo playerInfo,
		@Nullable Location location,
		@NonNull Chat chat,
		@NonNull Component message)
	{
		ConfigCache configCache = MSUtil.getConfigCache();
		if (chat == Chat.LOCAL && location != null)
		{
			Component localMessage = space()
				.append(playerInfo.getDefaultName())
				.append(text(" : "))
				.color(CHAT_MESSAGE_COLOR_PRIMARY)
				.hoverEvent(HoverEvent.showText(text("Натисніть, щоб написати приватне повідомлення цьому гравцю", NamedTextColor.GRAY)))
				.clickEvent(ClickEvent.suggestCommand("/pm {} ", playerInfo.getID())))
				.append(message)
				.color(CHAT_MESSAGE_COLOR_SECONDARY);
			String stringLocalMessage = serializeLegacyComponent(localMessage);

			sendLocalMessage(localMessage, location, configCache.localChatRadius);
			Bukkit.getScheduler().runTaskAsynchronously(new MSUtil(),
				() -> sendMessage(getTextChannelById(configCache.discordLocalChannelId), stringLocalMessage));
			sendInfo(stringLocalMessage);
			return;
		}

		if (chat != Chat.GLOBAL) return;
		// TODO: prefix to config.
		Component globalMessage = space()
			.append(text("[WM] ")
			.append(playerInfo.getDefaultName()
			.append(text(" : ")))
			.color(CHAT_MESSAGE_COLOR_PRIMARY)
			.hoverEvent(HoverEvent.showText(text("Натисніть, щоб написати приватне повідомлення цьому гравцю", NamedTextColor.GRAY)))
			.clickEvent(ClickEvent.suggestCommand("/pm {} ", playerInfo.getID())))
			.append(message)
			.color(CHAT_MESSAGE_COLOR_SECONDARY);
		String stringGlobalMessage = serializeLegacyComponent(globalMessage);

		sendGlobalMessage(globalMessage);
		Bukkit.getScheduler().runTaskAsynchronously(new MSUtil(), () ->
		{
			sendMessage(getTextChannelById(configCache.discordGlobalChannelId), stringGlobalMessage.replaceFirst("\\[WM]", ""));
			sendMessage(getTextChannelById(configCache.discordLocalChannelId), stringGlobalMessage);
		});
		sendInfo(stringGlobalMessage);
	}


	/**
	 * Send a private message.
	 * @param sender	private message sender
	 * @param receiver	private message receiver
	 * @param message	private message
	 * @return			True if sender or receiver equals null
	 * @deprecated
	 */
	@Deprecated
	public boolean sendPrivateMessage(
		@NonNull PlayerInfo sender,
		@NonNull PlayerInfo receiver,
		@NonNull Component message)
	{
		CommandSender commandSender = sender == MSUtil.getConsolePlayerInfo()
			? Bukkit.getConsoleSender()
			: sender.getOnlinePlayer();
		Player receiverPlayer = receiver.getOnlinePlayer();

		if (commandSender != null && receiverPlayer != null)
		{
			String privateMessage = serializeLegacyComponent(sender.getDefaultName()
				.append(text(MessageFormat.format(" -> {0} : ", receiver.getDefaultName()))
				.color(CHAT_MESSAGE_COLOR_PRIMARY)
				.append(message.color(CHAT_MESSAGE_COLOR_SECONDARY)));

			commandSender.sendMessage(
				Badges.SPEECH.append(text("Ви -> ")
				.append(receiver.getDefaultName()
				.append(text(" : ")))
				.hoverEvent(HoverEvent.showText(text("Натисніть, щоб написати приватне повідомлення цьому гравцю", NamedTextColor.GRAY)))
				.clickEvent(ClickEvent.suggestCommand("/pm " + receiver.getID() + " ")))
				.color(CHAT_MESSAGE_COLOR_PRIMARY))
				.append(message.color(CHAT_MESSAGE_COLOR_SECONDARY)));
			receiverPlayer.sendMessage(
				Badges.SPEECH.append(sender.getDefaultName().append(text(" -> Вам : "))
				.color(CHAT_MESSAGE_COLOR_PRIMARY)
				.hoverEvent(HoverEvent.showText(text("Натисніть, щоб написати приватне повідомлення цьому гравцю", NamedTextColor.GRAY)))
				.clickEvent(ClickEvent.suggestCommand("/pm " + sender.getID() + " ")))
				.append(message.color(CHAT_MESSAGE_COLOR_SECONDARY)));
			Bukkit.getScheduler().runTaskAsynchronously(new MSUtil(),
				() -> sendMessage(getTextChannelById(MSUtil.getConfigCache().discordLocalChannelId), privateMessage));
			sendInfo(privateMessage);
			return true;
		}
		return false;
	}

	/**
	 * Send roleplay event message to chat.
	 * @param sender			 player
	 * @param speech			 speech
	 * @param action			 action
	 * @param rolePlayActionType roleplay action type
	 * @deprecated
	 */
	@Deprecated
	public static void sendRPEventMessage(
		@NonNull Player sender,
		@NonNull Component speech,
		@NonNull Component action,
		@NonNull RolePlayActionType rolePlayActionType)
	{
		ConfigCache configCache = MSUtil.getConfigCache();
		PlayerInfoMap playerInfoMap = configCache.playerInfoMap;
		PlayerInfo playerInfo = playerInfoMap.getPlayerInfo(sender);
		Component fullMessage =
			switch (rolePlayActionType)
			{
				case DO ->
					text("* ", RP_MESSAGE_COLOR_PRIMARY)
						.append(action.color(RP_MESSAGE_COLOR_SECONDARY))
						.append(text(" * | ", RP_MESSAGE_COLOR_PRIMARY))
						.append(playerInfo.getGrayIDGoldName());
				case IT ->
					text("* ", RP_MESSAGE_COLOR_PRIMARY)
						.append(action.color(RP_MESSAGE_COLOR_SECONDARY))
						.append(text(" *", RP_MESSAGE_COLOR_PRIMARY));
				case TODO ->
					text("* ")
						.color(RP_MESSAGE_COLOR_PRIMARY)
						.append(speech
						.color(RP_MESSAGE_COLOR_SECONDARY))
						.append(text(" - ")
						.append(text(playerInfo.getPlayerFile().getPronouns().getSaidMessage())))
						.color(RP_MESSAGE_COLOR_PRIMARY)
						.append(space())
						.append(playerInfo.getGrayIDGoldName())
						.append(text(", ", RP_MESSAGE_COLOR_PRIMARY))
						.append(action
						.color(RP_MESSAGE_COLOR_SECONDARY))
						.append(text(" *", RP_MESSAGE_COLOR_PRIMARY));
				default ->
					text("* ", RP_MESSAGE_COLOR_PRIMARY)
						.append(playerInfo.getGrayIDGoldName())
						.append(space()
						.append(action.color(RP_MESSAGE_COLOR_SECONDARY)))
						.append(text(" *", RP_MESSAGE_COLOR_PRIMARY));
			};

		sendLocalMessage(Badges.YELLOW_EXCLAMATION_MARK.append(fullMessage), sender.getLocation(), configCache.localChatRadius);
		Bukkit.getScheduler().runTaskAsynchronously(new MSUtil(),
			() -> sendMessage(getTextChannelById(configCache.discordLocalChannelId), serializeLegacyComponent(fullMessage)));
		sendInfo(serializeLegacyComponent(fullMessage));
	}

	@Deprecated
	public void sendRPEventMessage(
		@NonNull Player player,
		@NonNull Component action,
		@NonNull RolePlayActionType rolePlayActionType)
	{
		sendRPEventMessage(player, Component.empty(), action, rolePlayActionType);
	}

	/**
	 * Send a death message.
	 * @param killed who killed
	 * @param killer by who
	 * @deprecated
	 */
	@Deprecated
	public static void sendDeathMessage(
		@NonNull Player killed,
		@Nullable Player killer)
	{
		ConfigCache configCache = MSUtil.getConfigCache();
		PlayerInfoMap playerInfoMap = configCache.playerInfoMap;
		Location deathLocation = killed.getLocation();
		PlayerInfo killedInfo = playerInfoMap.getPlayerInfo(killed);
		PlayerInfo killerInfo = killer == null
			? null
			: playerInfoMap.getPlayerInfo(killer);
		Component deathMessage = killerInfo == null
			? space()
				.append(killedInfo.getGoldenName()
				.append(space()))
				.append(text(killedInfo.getPlayerFile().getPronouns().getDeathMessage()))
				.color(JOIN_MESSAGE_COLOR_PRIMARY)
			: space()
				.append(killerInfo.getGoldenName()
				.append(space()))
				.append(text(killerInfo.getPlayerFile().getPronouns().getKillMessage())
				.color(JOIN_MESSAGE_COLOR_PRIMARY)
				.append(space()))
				.append(killedInfo.getGoldenName());
		String stringDeathMessage = serializeLegacyComponent(deathMessage);

		killedInfo.setLastDeathLocation(deathLocation);
		sendGlobalMessage(deathMessage);
		Bukkit.getScheduler().runTaskAsynchronously(new MSUtil(), () ->
		{
			sendActionMessage(killed, getTextChannelById(configCache.discordGlobalChannelId), stringDeathMessage, 16757024);
			sendActionMessage(killed, getTextChannelById(configCache.discordLocalChannelId), stringDeathMessage, 16757024);
		});
		sendInfo(stringDeathMessage);

		sendInfo(text(MessageFormat.format(
			"Світ та координати смерті гравця: \"{0}\" ({1}) : {2} {3} {4} {5}",
			killedInfo.getDefaultName(), killed.getName,
			deathLocation.getWorld().getName(),
			deathLocation.getBlockX(), deathLocation.getBlockY(), deathLocation.getBlockZ()))
		);
	}

	/**
	 * Send a message about joining the server.
	 * @param playerInfo PlayerInfo object of joined player
	 * @deprecated
	 */
	// Refactor code to remove PlayerInfo.
	@Deprecated
	public void sendJoinMessage(@NonNull PlayerInfo playerInfo)
	{
		Player player = playerInfo.getOnlinePlayer();

		if (player == null || !playerInfo.isOnline(true)) return;

		ConfigCache configCache = MSUtil.getConfigCache();
		Component joinMessage = playerInfo.getGoldenName()
			.append(space()))
			.append(text(playerInfo.getPlayerFile().getPronouns().getJoinMessage()))
			.color(JOIN_MESSAGE_COLOR_PRIMARY);
		String stringJoinMessage = serializeLegacyComponent(joinMessage);

		sendGlobalMessage(joinMessage);
		Bukkit.getScheduler().runTaskAsynchronously(new MSUtil(), () ->
		{
			sendActionMessage(player, getTextChannelById(configCache.discordGlobalChannelId), stringJoinMessage, 65280);
			sendActionMessage(player, getTextChannelById(configCache.discordLocalChannelId), stringJoinMessage, 65280);
		});
		sendInfo(stringJoinMessage);
	}

	/**
	 * Send message about leaving the server.
	 * @param playerInfo	playerInfo
	 * @param player		player
	 * @deprecated
	 */
	@Deprecated
	public void sendQuitMessage(
		@NonNull PlayerInfo playerInfo,
		@NonNull Player player)
	{
		if (!playerInfo.isOnline()) return;
		ConfigCache configCache = MSUtil.getConfigCache();
		Component quitMessage = playerInfo.getGoldenName()
			.append(space()))
			.append(text(playerInfo.getPlayerFile().getPronouns().getQuitMessage()))
			.color(JOIN_MESSAGE_COLOR_PRIMARY);
		String stringQuitMessage = serializeLegacyComponent(quitMessage);

		sendGlobalMessage(quitMessage);
		Bukkit.getScheduler().runTaskAsynchronously(new MSUtil(), () ->
		{
			// TODO: Move channel id to config.
			sendActionMessage(player, getTextChannelById(configCache.discordGlobalChannelId), stringQuitMessage, 16711680);
			sendActionMessage(player, getTextChannelById(configCache.discordLocalChannelId), stringQuitMessage, 16711680);
		});
		sendInfo(stringQuitMessage);
	}

	@Deprecated
	private void sendActionMessage(
		@NonNull Player player,
		TextChannel textChannel,
		@NonNull String actionMessage,
		int colorRaw)
	{
		if (DiscordUtil.getJda() == null) return;
		DiscordUtil.queueMessage(textChannel,
			DiscordSRV.translateMessage(
				new MessageFormat(
					"",
					actionMessage,
					"",
					DiscordSRV.getAvatarUrl(player),
					"",
					"",
					"",
					"",
					"",
					"",
					"",
					null,
					colorRaw,
					null,
					false,
					DiscordUtil.getJda().getSelfUser().getEffectiveAvatarUrl(),
					DiscordSRV.getPlugin().getMainGuild() == null
						? DiscordUtil.getJda().getSelfUser().getName()
						: DiscordSRV.getPlugin().getMainGuild().getSelfMember().getEffectiveName()),
				(content, needsEscape) -> PlaceholderUtil.replacePlaceholdersToDiscord(content, player)), true);
	}

	private final class Colors
	{
		// TODO: Move color values to config.
		final TextColor
			CHAT_MESSAGE_COLOR_PRIMARY = TextColor.fromHexString("#aba494"),
			CHAT_MESSAGE_COLOR_SECONDARY = TextColor.fromHexString("#f1f0e3"),
			JOIN_MESSAGE_COLOR_PRIMARY = TextColor.fromHexString("#ffef93"),
			JOIN_MESSAGE_COLOR_SECONDARY = TextColor.fromHexString("#fcf5c7"),
			RP_MESSAGE_COLOR_PRIMARY = TextColor.fromHexString("#ffaa00"),
			RP_MESSAGE_COLOR_SECONDARY = TextColor.fromHexString("#ffc369");
	}
}