/*
 *   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 com.velocitypowered.api.proxy.ServerConnection;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import de.steamwar.linkage.Linked;
import de.steamwar.velocitycore.*;
import de.steamwar.velocitycore.util.BauLock;
import de.steamwar.command.PreviousArguments;
import de.steamwar.command.SWCommand;
import de.steamwar.command.TypeMapper;
import de.steamwar.messages.Chatter;
import de.steamwar.messages.PlayerChatter;
import de.steamwar.persistent.Bauserver;
import de.steamwar.persistent.Storage;
import de.steamwar.persistent.Subserver;
import de.steamwar.sql.*;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

@Linked
public class TpCommand extends SWCommand {

    public TpCommand(){
        super("join", "tp", "teleport");
    }

    @Register
    public void genericCommand(Chatter sender) {
        sender.system(Event.get() == null ? "TP_USAGE" : "TP_USAGE_EVENT");
    }

    @Register
    public void teleportCommand(PlayerChatter sender, @Mapper("to") String to, String... rest) {
        RegisteredServer server = getTarget(to);

        //Give control of teleport command to server
        Player p = sender.getPlayer();
        if (server == null || server.getPlayersConnected().contains(p)) {
            if (rest.length == 0) {
                p.spoofChatInput("/tp " + to);
            } else {
                p.spoofChatInput("/tp " + to + " " + String.join(" ", rest));
            }
            return;
        }

        teleport(sender, server);
    }

    @Mapper("to")
    @Cached(cacheDuration = 10)
    public TypeMapper<String> tabCompleter() {
        return new TypeMapper<>() {
            @Override
            public String map(Chatter sender, PreviousArguments previousArguments, String s) {
                return s;
            }

            @Override
            public Collection<String> tabCompletes(Chatter sender, PreviousArguments previousArguments, String s) {
                List<String> list = new ArrayList<>();
                for (Player player : VelocityCore.getProxy().getAllPlayers()) {
                    list.add(player.getUsername());
                }
                if (Event.get() != null) {
                    EventStarter.getEventServer().keySet().forEach(teamId -> {
                        Team team = Team.get(teamId);
                        list.add(team.getTeamName());
                        list.add(team.getTeamKuerzel());
                    });
                }
                if (Storage.teamServers.containsValue(sender.getPlayer().getCurrentServer().orElseThrow().getServerInfo())) {
                    Storage.directTabItems.getOrDefault(sender.getPlayer(), Collections.emptyMap()).forEach((uuid, item) -> list.add(item.getProfile().getName()));
                }
                return list;
            }
        };
    }

    public static void teleport(PlayerChatter sender, RegisteredServer server) {
        if(CheckCommand.isChecking(sender.getPlayer())){
            sender.system("CHECK_CHECKING");
            return;
        }

        Subserver subserver = Subserver.getSubserver(server.getServerInfo());
        if(subserver == null) {
            sender.getPlayer().createConnectionRequest(server).fireAndForget();
            return;
        }

        if(Subserver.isArena(subserver)) {
            if (PunishmentCommand.isPunishedWithMessage(sender, Punishment.PunishmentType.NoFightServer))
                return;
        } else if(Subserver.isBuild(subserver)) {
            Bauserver bauserver = (Bauserver) subserver;
            Player checker = VelocityCore.getProxy().getPlayer(bauserver.getOwner()).orElse(null);
            if (checker != null && CheckCommand.isChecking(checker)) {
                if (!sender.user().hasPerm(UserPerm.CHECK) && CheckCommand.getCheckingSchem(checker).getOwner() != sender.user().getId()) {
                    sender.system("JOIN_PLAYER_BLOCK");
                    return;
                }
            } else if (BauLock.isLocked(SteamwarUser.get(bauserver.getOwner()), sender.user())) {
                sender.system("BAU_LOCKED_NOALLOWED");
                Chatter.of(bauserver.getOwner()).system("BAU_LOCK_BLOCKED", sender);
                return;
            } else if (!bauserver.getOwner().equals(sender.user().getUUID()) && BauweltMember.getBauMember(bauserver.getOwner(), sender.user().getUUID()) == null) {
                SubserverSystem.sendDeniedMessage(sender, bauserver.getOwner());
                sender.system("JOIN_PLAYER_BLOCK");
                return;
            }
        } else if(Subserver.isBuilder(subserver)) {
            if(!sender.user().hasPerm(UserPerm.BUILD)) {
                sender.system("JOIN_PLAYER_BLOCK");
                return;
            }
        }

        SubserverSystem.sendPlayer(subserver, sender.getPlayer());
    }

    private static RegisteredServer getTarget(String arg) {
        RegisteredServer server = null;

        //Get target player server
        Player target = VelocityCore.getProxy().getPlayer(arg).orElse(null);
        if(target != null)
            server = target.getCurrentServer().map(ServerConnection::getServer).orElse(server);

        //Get target team event arena
        if(server == null){
            Team team = Team.get(arg);
            if(team != null){
                Subserver eventArena = EventStarter.getEventServer().get(team.getTeamId());
                if(eventArena != null && Subserver.getServerList().contains(eventArena))
                    server = eventArena.getRegisteredServer();
            }
        }

        return server;
    }
}
