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

import com.velocitypowered.api.proxy.Player;
import de.steamwar.command.SWCommand;
import de.steamwar.linkage.EventMode;
import de.steamwar.linkage.Linked;
import de.steamwar.messages.Chatter;
import de.steamwar.messages.Message;
import de.steamwar.messages.PlayerChatter;
import de.steamwar.persistent.Arenaserver;
import de.steamwar.persistent.Subserver;
import de.steamwar.velocitycore.ArenaMode;
import de.steamwar.velocitycore.ServerStarter;
import de.steamwar.velocitycore.inventory.SWInventory;
import de.steamwar.velocitycore.inventory.SWItem;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextDecoration;

@Linked
@EventMode(false)
public class FightCommand extends SWCommand {

    public FightCommand() {
        super("fight", "f");
    }

    private static void getModes(Chatter sender, String precommand, boolean historic){
        Component start = Component.empty();
        for(ArenaMode mode : ArenaMode.getAllModes()){
            if (!mode.isActive() || mode.isHistoric() != historic)
                continue;

            String command = precommand + mode.getChatName();
            start = start.append(Component
                    .text(mode.getChatName() + " ")
                    .color(NamedTextColor.GRAY)
                    .decorate(TextDecoration.BOLD)
                    .hoverEvent(HoverEvent.showText(Component.text(("§e" + command))))
                    .clickEvent(ClickEvent.runCommand(command)));
        }

        sender.sendMessage(start);
    }

    static void createArena(PlayerChatter sender, String precommand, boolean allowMerging, ArenaMode arenaMode, String map, boolean historic, FightCallback callback) {
        if (arenaMode == null) {
            getModes(sender, precommand, historic);
            return;
        }

        if (map == null)
            map = arenaMode.getRandomMap();

        if (!allowMerging) {
            callback.run(sender, arenaMode, map);
        } else {
            suggestMerging(sender, arenaMode, map, callback);
        }
    }

    private static void suggestMerging(PlayerChatter sender, ArenaMode mode, String map, FightCallback declineMerge) {
        Arenaserver mergable = null;
        synchronized (Subserver.getServerList()) {
            for (Subserver subserver : Subserver.getServerList()) {
                if(subserver instanceof Arenaserver arenaserver &&
                        (mode.getInternalName().equals(arenaserver.getMode()) && arenaserver.isAllowMerge() && arenaserver.getRegisteredServer().getPlayersConnected().size() == 1)) {
                    mergable = arenaserver;
                    break;
                }
            }
        }

        if(mergable == null) {
            declineMerge.run(sender, mode, map);
            return;
        }

        SWInventory inventory = new SWInventory(sender, 9, new Message("FIGHT_MERGE_TITLE"));
        inventory.addItem(0, new SWItem(new Message("FIGHT_MERGE_DECLINE"), 1), click -> {
            inventory.close();
            declineMerge.run(sender, mode, map);
        });
        Arenaserver finalMergable = mergable;
        SWItem item = new SWItem(new Message("FIGHT_MERGE_INFO", mode.getGameName(), finalMergable.getMap()), 11);
        item.addLore(new Message("FIGHT_MERGE_INFO_LORE_1", finalMergable.getRegisteredServer().getPlayersConnected().toArray(new Player[1])[0].getUsername()));
        inventory.addItem(4, item, click -> {});
        inventory.addItem(8, new SWItem(new Message("FIGHT_MERGE_ACCEPT"), 10), click -> {
            if(Subserver.getServerList().contains(finalMergable)) {
                finalMergable.sendPlayer(sender.getPlayer());
            } else {
                sender.system("FIGHT_MERGE_OFFLINE");
                declineMerge.run(sender, mode, map);
            }
        });
        inventory.open();
    }

    @Register
    public void fight(@Validator("arenaPlayer") PlayerChatter sender, @Mapper("nonHistoricArenaMode") @OptionalValue("") @AllowNull ArenaMode arenaMode, @Mapper("arenaMap") @OptionalValue("") @AllowNull String map) {
        createArena(sender, "/fight ", true, arenaMode, map, false,
                (p, mode, m) -> new ServerStarter().arena(mode, m).blueLeader(p.getPlayer()).callback(
                        arena -> Chatter.broadcast().system("FIGHT_BROADCAST", new Message("FIGHT_BROADCAST_HOVER", p.getPlayer().getUsername()), ClickEvent.runCommand("/arena " + arena.getServer().getName()), mode.getGameName(), p.getPlayer().getUsername())
                ).start()
        );
    }

    public interface FightCallback {
        void run(PlayerChatter player, ArenaMode mode, String map);
    }
}
