/*
 *   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.warp;

import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.utils.ListChatView;
import de.steamwar.bausystem.worlddata.WorldData;
import de.steamwar.command.SWCommand;
import de.steamwar.command.SWCommandUtils;
import de.steamwar.command.TypeMapper;
import de.steamwar.linkage.Linked;
import de.steamwar.linkage.api.Disable;
import de.steamwar.linkage.api.Enable;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.entity.Player;
import yapion.hierarchy.types.YAPIONObject;

import java.util.ArrayList;

@Linked
public class WarpCommand extends SWCommand implements Disable, Enable {

    private static final String[] FORBIDDEN_NAMES = new String[]{
            "add", "create", "delete", "list", "info", "gui"
    };

    public WarpCommand() {
        super("warp");
    }

    @ClassMapper(Warp.class)
    public static TypeMapper<Warp> getWarpMapper() {
        return SWCommandUtils.createMapper(Warp::getWarp, (commandSender, s) -> new ArrayList<>(Warp.getWarpNames()));
    }

    @Register(value = "add", description = "WARP_HELP_ADD")
    @Register("create")
    public void addWarp(@Validator Player player, String name) {
        for (String forbiddenName : FORBIDDEN_NAMES) {
            if (name.equalsIgnoreCase(forbiddenName)) {
                BauSystem.MESSAGE.send("WARP_NAME_RESERVED", player, name);
                return;
            }
        }
        if (Warp.getWarp(name) != null) {
            BauSystem.MESSAGE.send("WARP_EXISTS", player, name);
            return;
        }
        new Warp(name, player);
        BauSystem.MESSAGE.send("WARP_CREATED", player, name);
    }

    @Register(description = "WARP_HELP_TELEPORT")
    public void tpWarp(Player player, Warp warp) {
        warp.teleport(player);
    }

    @Register(value = "delete", description = "WARP_HELP_DELETE")
    public void deleteWarp(@Validator Player player, Warp warp) {
        warp.delete();
        BauSystem.MESSAGE.send("WARP_DELETED", player, warp.getName());
    }

    @Register(value = "gui", description = "WARP_HELP_GUI")
    public void gui(Player player) {
        WarpGui.openGui(player);
    }

    @Register(value = "list", description = "WARP_HELP_LIST")
    public void listWarps(Player player) {
        listWarps(player, 0);
    }

    @Register("list")
    public void listWarps(Player player, int page) {
        ListChatView.chatView(player, Warp.getWarps(), page, warp -> {
            TextComponent component = new TextComponent();
            component.setText(warp.getName());
            component.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/warp " + warp.getName()));
            component.setColor(ChatColor.YELLOW);
            component.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.fromLegacyText(BauSystem.MESSAGE.parse("WARP_TELEPORT_HOVER", player, warp.getName()))));
            return component;
        }, (beforePageComponent, beforePage) -> {
            beforePageComponent.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder(BauSystem.MESSAGE.parse("LIST_PREVIOUS_PAGE", player)).create()));
            beforePageComponent.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/warp list " + beforePage));
        }, (afterPageComponent, afterPage) -> {
            afterPageComponent.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder(BauSystem.MESSAGE.parse("LIST_NEXT_PAGE", player)).create()));
            afterPageComponent.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/warp list " + afterPage));
        });
    }

    @Register(value = "info", description = "WARP_HELP_INFO")
    public void warpInfo(Player player, Warp warp) {
        BauSystem.MESSAGE.send("COMMAND_HELP_HEAD", player, warp.getName());
        BauSystem.MESSAGE.sendPrefixless("WARP_INFO_NAME", player, warp.getName());
        BauSystem.MESSAGE.sendPrefixless("WARP_LOC_X", player, warp.getLocation().getX());
        BauSystem.MESSAGE.sendPrefixless("WARP_LOC_Y", player, warp.getLocation().getY());
        BauSystem.MESSAGE.sendPrefixless("WARP_LOC_Z", player, warp.getLocation().getZ());
        BauSystem.MESSAGE.sendPrefixless("WARP_GUI_DISTANCE", player, warp.getLocation().distance(player.getLocation()));
    }

    @Linked
    public static class WarpsLink extends SWCommand {

        public WarpsLink() {
            super("warps");
        }

        @Register(help = true)
        public void genericCommand(Player player, String... args) {
            player.performCommand("warp list " + String.join(" ", args));
        }
    }

    @Override
    public void enable() {
        WorldData.getWarpData().forEach((name, yapionAnyType) -> {
            new Warp(name, (YAPIONObject) yapionAnyType);
        });
        Warp.enable();
    }

    @Override
    public void disable() {
        YAPIONObject yapionObject = WorldData.getWarpData();
        for (Warp warp : Warp.getWarps()) {
            yapionObject.add(warp.getName(), warp.output());
        }
    }
}
