package emu.grasscutter.command.commands;

import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.inventory.Inventory;
import emu.grasscutter.game.inventory.ItemType;
import emu.grasscutter.game.player.Player;
import lombok.Setter;

import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.regex.Pattern;
import java.util.stream.Stream;

import static emu.grasscutter.command.CommandHelpers.*;

@Command(
    label = "clear",
    usage = {"(all|wp|art|mat) [lv<max level>] [r<max refinement>] [<max rarity>*]"},
    permission = "player.clearinv",
    permissionTargeted = "player.clearinv.others")
public final class ClearCommand implements CommandHandler {

    private static final Map<Pattern, BiConsumer<ClearItemParameters, Integer>> intCommandHandlers = Map.ofEntries(
        Map.entry(lvlRegex, ClearItemParameters::setLvl),
        Map.entry(refineRegex, ClearItemParameters::setRefinement),
        Map.entry(rankRegex, ClearItemParameters::setRank)
    );

    private static class ClearItemParameters {
        @Setter public int lvl = 1;
        @Setter public int refinement = 1;
        @Setter public int rank = 4;
    }

    private Stream<GameItem> getOther(ItemType type, Inventory playerInventory, ClearItemParameters param) {
        return playerInventory.getItems().values().stream()
                .filter(item -> item.getItemType() == type)
                .filter(item -> item.getItemData().getRankLevel() <= param.rank)
                .filter(item -> !item.isLocked() && !item.isEquipped());
    }

    private Stream<GameItem> getWeapons(Inventory playerInventory, ClearItemParameters param) {
        return getOther(ItemType.ITEM_WEAPON, playerInventory, param)
                .filter(item -> item.getLevel() <= param.lvl)
                .filter(item -> item.getRefinement() < param.refinement);
    }

    private Stream<GameItem> getRelics(Inventory playerInventory, ClearItemParameters param) {
        return getOther(ItemType.ITEM_RELIQUARY, playerInventory, param)
                .filter(item -> item.getLevel() <= param.lvl + 1);
    }

    @Override
    public void execute(Player sender, Player targetPlayer, List<String> args) {
        Inventory playerInventory = targetPlayer.getInventory();
        ClearItemParameters param = new ClearItemParameters();

        // Extract any tagged int arguments (e.g. "lv90", "x100", "r5")
        parseIntParameters(args, param, intCommandHandlers);

        if (args.size() < 1) {
            sendUsageMessage(sender);
            return;
        }

        String playerString = targetPlayer.getNickname();  // Should probably be UID instead but whatever
        switch (args.get(0)) {
            case "wp" -> {
                playerInventory.removeItems(getWeapons(playerInventory, param).toList());
                CommandHandler.sendTranslatedMessage(sender, "commands.clear.weapons", playerString);
            }
            case "art" -> {
                playerInventory.removeItems(getRelics(playerInventory, param).toList());
                CommandHandler.sendTranslatedMessage(sender, "commands.clear.artifacts", playerString);
            }
            case "mat" -> {
                playerInventory.removeItems(getOther(ItemType.ITEM_MATERIAL, playerInventory, param).toList());
                CommandHandler.sendTranslatedMessage(sender, "commands.clear.materials", playerString);
            }
            case "all" -> {
                playerInventory.removeItems(getRelics(playerInventory, param).toList());
                CommandHandler.sendTranslatedMessage(sender, "commands.clear.artifacts", playerString);
                playerInventory.removeItems(getWeapons(playerInventory, param).toList());
                CommandHandler.sendTranslatedMessage(sender, "commands.clear.weapons", playerString);
                playerInventory.removeItems(getOther(ItemType.ITEM_MATERIAL, playerInventory, param).toList());
                CommandHandler.sendTranslatedMessage(sender, "commands.clear.materials", playerString);
                playerInventory.removeItems(getOther(ItemType.ITEM_FURNITURE, playerInventory, param).toList());
                CommandHandler.sendTranslatedMessage(sender, "commands.clear.furniture", playerString);
                playerInventory.removeItems(getOther(ItemType.ITEM_DISPLAY, playerInventory, param).toList());
                CommandHandler.sendTranslatedMessage(sender, "commands.clear.displays", playerString);
                playerInventory.removeItems(getOther(ItemType.ITEM_VIRTUAL, playerInventory, param).toList());
                CommandHandler.sendTranslatedMessage(sender, "commands.clear.virtuals", playerString);
                CommandHandler.sendTranslatedMessage(sender, "commands.clear.everything", playerString);
            }
        }
    }
}
