package dev.m1sk9.lunaticChat.paper.command.impl

import com.mojang.brigadier.arguments.StringArgumentType
import com.mojang.brigadier.builder.LiteralArgumentBuilder
import com.mojang.brigadier.suggestion.Suggestions
import com.mojang.brigadier.suggestion.SuggestionsBuilder
import dev.m1sk9.lunaticChat.engine.command.CommandResult
import dev.m1sk9.lunaticChat.engine.permission.LunaticChatPermissionNode
import dev.m1sk9.lunaticChat.paper.LunaticChat
import dev.m1sk9.lunaticChat.paper.chat.handler.DirectMessageHandler
import dev.m1sk9.lunaticChat.paper.command.annotation.Command
import dev.m1sk9.lunaticChat.paper.command.annotation.Permission
import dev.m1sk9.lunaticChat.paper.command.annotation.PlayerOnly
import dev.m1sk9.lunaticChat.paper.command.core.CommandContext
import dev.m1sk9.lunaticChat.paper.command.core.LunaticCommand
import dev.m1sk9.lunaticChat.paper.i18n.LanguageManager
import dev.m1sk9.lunaticChat.paper.i18n.MessageFormatter
import io.papermc.paper.command.brigadier.CommandSourceStack
import io.papermc.paper.command.brigadier.Commands
import org.bukkit.Bukkit
import java.util.concurrent.CompletableFuture

@Command(
    name = "tell",
    aliases = ["t", "msg", "m", "w", "whisper"],
    description = "",
)
@Permission(LunaticChatPermissionNode.Tell::class)
@PlayerOnly
class TellCommand(
    plugin: LunaticChat,
    private val directMessageHandler: DirectMessageHandler,
    private val languageManager: LanguageManager,
) : LunaticCommand(plugin) {
    override val description: String
        get() = languageManager.getMessage("commandDescription.tell")

    override fun buildCommand(): LiteralArgumentBuilder<CommandSourceStack> =
        Commands
            .literal(name)
            .then(
                Commands
                    .argument("player", StringArgumentType.word())
                    .suggests { _, builder -> suggestOnlinePlayers(builder) }
                    .then(
                        Commands
                            .argument("message", StringArgumentType.greedyString())
                            .executes { ctx ->
                                val context = wrapContext(ctx)
                                checkPlayerOnly(context)?.let { return@executes handleResult(context, it) }

                                val targetName = StringArgumentType.getString(ctx, "player")
                                val message = StringArgumentType.getString(ctx, "message")

                                val result = execute(context, targetName, message)
                                handleResult(context, result)
                            },
                    ),
            )

    private fun execute(
        ctx: CommandContext,
        targetName: String,
        message: String,
    ): CommandResult {
        val sender = ctx.requirePlayer()
        val recipient =
            Bukkit.getPlayer(targetName)
                ?: return CommandResult.Failure(
                    MessageFormatter.formatError(
                        languageManager.getMessage("directMessage.targetOffline", mapOf("target" to targetName)),
                    ),
                )

        if (recipient.uniqueId == sender.uniqueId) {
            return CommandResult.Failure(
                MessageFormatter.formatError(
                    languageManager.getMessage("directMessage.yourself"),
                ),
            )
        }

        directMessageHandler.sendDirectMessage(sender, recipient, message)

        return CommandResult.Success
    }

    private fun suggestOnlinePlayers(builder: SuggestionsBuilder): CompletableFuture<Suggestions> {
        val input = builder.remaining.lowercase()
        Bukkit
            .getOnlinePlayers()
            .filter { it.name.lowercase().startsWith(input) }
            .forEach { builder.suggest(it.name) }
        return builder.buildFuture()
    }
}
