/*
 * This file is a part of the SteamWar software.
 *
 * Copyright (C) 2021  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.slaves.panzern;

import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.Permission;
import de.steamwar.bausystem.SWUtils;
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.command.TypeValidator;
import de.steamwar.linkage.Linked;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Linked
public class PanzernCommand extends SWCommand {

    public PanzernCommand() {
        super("panzern", "panzersklave");
        addDefaultHelpMessage("PANZERN_HELP");
        addDefaultHelpMessage("PANZERN_PREPARE1");
        addDefaultHelpMessage("PANZERN_PREPARE2");
        addDefaultHelpMessage("PANZERN_PREPARE3");
        addDefaultHelpMessage("PANZERN_PREPARE4");
    }

    @Register
    public void panzerSelection(@Validator Player player, @Mapper("block") Material blockMaterial, @Mapper("slab") Material slabMaterial) {
        Pair<Location, Location> selection = WorldEditUtils.getSelection(player);
        if (selection == null) {
            BauSystem.MESSAGE.send("PANZERN_NO_WORLDEDIT", player);
            return;
        }
        Panzern panzern = new Panzern(player, selection.getKey(), selection.getValue(), player.getLocation(), blockMaterial, slabMaterial);
        new BukkitRunnable() {
            @Override
            public void run() {
                int blockLeft = panzern.blocksLeft();
                long totalTime = 0;
                long blocks = 0;
                while (true) {
                    if (!panzern.hasNext()) {
                        BauSystem.MESSAGE.send("PANZERN_DONE", player);
                        panzern.getEditSession().flushSession();
                        WorldEditUtils.addToPlayer(player, panzern.getEditSession());
                        cancel();
                        return;
                    }
                    long time = System.currentTimeMillis();
                    panzern.next();
                    totalTime += System.currentTimeMillis() - time;
                    blocks++;
                    if (totalTime > 40) {
                        break;
                    }
                }
                long finalBlocks = blocks;
                Bukkit.getOnlinePlayers().forEach(p -> {
                    SWUtils.sendToActionbar(p, BauSystem.MESSAGE.parse("PANZERN_PROGRESS", p, panzern.blocksLeft(), finalBlocks * 20, panzern.blocksLeft() - blockLeft));
                });
            }
        }.runTaskTimer(BauSystem.getInstance(), 1, 1);
    }

    @Mapper(value = "block", local = true)
    private TypeMapper<Material> blockMapper() {
        Set<String> strings = new HashSet<>();
        for (Material material : Material.values()) {
            if (!material.isBlock()) {
                continue;
            }
            strings.add(material.name().toLowerCase());
        }
        return new TypeMapper<Material>() {
            @Override
            public List<String> tabCompletes(CommandSender commandSender, PreviousArguments previousArguments, String s) {
                return new ArrayList<>(strings);
            }

            @Override
            public Material map(CommandSender commandSender, PreviousArguments previousArguments, String s) {
                if (strings.contains(s.toLowerCase())) {
                    return Material.valueOf(s.toUpperCase());
                }
                return null;
            }
        };
    }

    @Mapper(value = "slab", local = true)
    private TypeMapper<Material> slabMapper() {
        Set<String> strings = new HashSet<>();
        for (Material material : Material.values()) {
            if (!material.isBlock()) {
                continue;
            }
            if (material.name().contains("STAIRS") || material.name().contains("SLAB") ||  material.name().contains("GLASS")) {
                strings.add(material.name().toLowerCase());
            }
        }
        return new TypeMapper<Material>() {
            @Override
            public List<String> tabCompletes(CommandSender commandSender, PreviousArguments previousArguments, String s) {
                return new ArrayList<>(strings);
            }

            @Override
            public Material map(CommandSender commandSender, PreviousArguments previousArguments, String s) {
                if (strings.contains(s.toLowerCase())) {
                    return Material.valueOf(s.toUpperCase());
                }
                return null;
            }
        };
    }
}
