/*
 *   This file is a part of the SteamWar software.
 *
 *   Copyright (C) 2025 SteamWar.de-Serverteam
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Affero General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *   GNU Affero General Public License for more details.
 *
 *   You should have received a copy of the GNU Affero General Public License
 *   along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

package de.steamwar.bausystem.features.worldedit;

import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import de.steamwar.bausystem.features.world.WorldEditListener;
import de.steamwar.bausystem.features.worldedit.utils.SpecialReplace;
import de.steamwar.bausystem.region.flags.ColorMode;
import de.steamwar.bausystem.shared.Pair;
import de.steamwar.bausystem.utils.WorldEditUtils;
import de.steamwar.command.PreviousArguments;
import de.steamwar.command.SWCommand;
import de.steamwar.command.TypeMapper;
import de.steamwar.linkage.Linked;
import lombok.SneakyThrows;
import org.bukkit.Material;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;

import java.util.*;
import java.util.stream.Collectors;

@Linked
public class ColorReplaceCommand extends SWCommand {

    public ColorReplaceCommand() {
        super("/colorreplace", "/cr");
    }

    private Set<String> types = new HashSet<>();

    {
        WorldEditListener.addOtherCommand("//colorreplace");
        WorldEditListener.addOtherCommand("//cr");
        for (Material value : Material.values()) {
            if (value.name().startsWith("WHITE_")) {
                types.add(value.name().substring(6));
            }
        }
    }

    @Register(description = "COLORREPLACE_HELP")
    @SneakyThrows
    public void genericCommand(@Validator Player player, Pair<Integer, ColorMode> from, ColorMode to) {
        if (from.getValue() == to) {
            BukkitAdapter.adapt(player).printInfo(TranslatableComponent.of("worldedit.replace.replaced", new Component[]{TextComponent.of(0)}));
            return;
        }

        Map<String, String> replacements = new HashMap<>();
        for (String type : types) {
            replacements.put("minecraft:" + from.getValue().name().toLowerCase() + "_" + type.toLowerCase(), "minecraft:" + to.name().toLowerCase() + "_" + type.toLowerCase());
        }

        try {
            Region region = WorldEditUtils.getRegion(player);
            EditSession editSession = WorldEditUtils.getEditSession(player);

            SpecialReplace specialReplace = new SpecialReplace(editSession, replacements, from.getKey());
            int affected = editSession.replaceBlocks(region, specialReplace, specialReplace);
            editSession.flushSession();
            WorldEditUtils.addToPlayer(player, editSession);
            BukkitAdapter.adapt(player).printInfo(TranslatableComponent.of("worldedit.replace.replaced", new Component[]{TextComponent.of(affected)}));
        } catch (IncompleteRegionException e) {
            BukkitAdapter.adapt(player).printError(TranslatableComponent.of("worldedit.error.incomplete-region"));
        }
    }

    @ClassMapper(value = Pair.class, local = true)
    public TypeMapper<Pair<Integer, ColorMode>> typeMapper() {
        return new TypeMapper<Pair<Integer, ColorMode>>() {
            @Override
            public Pair<Integer, ColorMode> map(CommandSender commandSender, PreviousArguments previousArguments, String s) {
                if (s.contains("%")) {
                    String[] split = s.split("%");
                    if (split.length != 2) {
                        return null;
                    }
                    ColorMode color = ColorMode.valueOf(split[1].toUpperCase());
                    try {
                        return new Pair<>(Integer.parseInt(split[0]), color);
                    } catch (NumberFormatException e) {
                        return null;
                    }
                }
                return new Pair<>(100, ColorMode.valueOf(s.toUpperCase()));
            }

            @Override
            public Collection<String> tabCompletes(CommandSender commandSender, PreviousArguments previousArguments, String s) {
                if (s.matches("[0-9].*")) {
                    if (s.contains("%")) {
                        String sub = s.substring(0, s.indexOf("%") + 1);
                        return Arrays.stream(ColorMode.values()).map(ColorMode::name).map(t -> sub + t.toLowerCase()).collect(Collectors.toSet());
                    } else {
                        return Arrays.asList(s);
                    }
                } else {
                    return Arrays.stream(ColorMode.values()).map(ColorMode::name).map(String::toLowerCase).collect(Collectors.toSet());
                }
            }
        };
    }
}
