/*
 *   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.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerInfo;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.velocity.platform.VelocityViaConfig;
import de.steamwar.command.SWCommand;
import de.steamwar.command.SWCommandUtils;
import de.steamwar.command.TypeMapper;
import de.steamwar.command.TypeValidator;
import de.steamwar.linkage.Linked;
import de.steamwar.messages.Chatter;
import de.steamwar.messages.Message;
import de.steamwar.messages.PlayerChatter;
import de.steamwar.sql.Punishment;
import de.steamwar.sql.SteamwarUser;
import de.steamwar.sql.UserPerm;
import de.steamwar.velocitycore.ArenaMode;
import de.steamwar.velocitycore.ServerVersion;
import de.steamwar.velocitycore.VelocityCore;
import lombok.Getter;

import java.io.File;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;

@Linked
public class DevCommand extends SWCommand {

    private final File devServerDir = new File("/configs/DevServer");
    @Getter
    private static final Map<String, RegisteredServer> devServers = new HashMap<>();

    public DevCommand() {
        super("dev");
    }

    @Register
    public void simpleCommand(@Validator PlayerChatter sender) {
        updateDevServers();
        if (devServers.isEmpty()) {
            sender.system("DEV_NO_SERVER");
            return;
        } else if (devServers.size() == 1) {
            devServers.values().stream().findAny().ifPresent(server -> sender.getPlayer().createConnectionRequest(server).fireAndForget());
            return;
        }

        RegisteredServer server = devServers.get(sender.getPlayer().getUsername().toLowerCase());
        if (server == null) {
            sender.system("DEV_UNKNOWN_SERVER");
            return;
        }

        sender.getPlayer().createConnectionRequest(server).fireAndForget();
    }

    @Register(value = "reloadmodes")
    public void reloadModes(Chatter sender) {
        if (!sender.user().hasPerm(UserPerm.ADMINISTRATION)) return;

        try {
            ArenaMode.init();
            sender.system("DEV_RELOAD_MODES_OK");
        } catch (Exception e) {
            sender.system("DEV_RELOAD_MODES_ERROR", e.getMessage());
        }
    }

    @Register
    public void selectedCommand(@Validator PlayerChatter sender, @Mapper("dev") String name) {
        updateDevServers();
        RegisteredServer server = devServers.get(name.toLowerCase());
        if (server == null) {
            sender.system("DEV_NO_SERVER");
            return;
        }

        sender.getPlayer().createConnectionRequest(server).fireAndForget();
    }

    @ClassValidator(value = PlayerChatter.class, local = true)
    public TypeValidator<PlayerChatter> punishmentGuardChecker() {
        return (sender, value, messageSender) -> {
            if (sender.user().isPunished(Punishment.PunishmentType.NoDevServer)) {
                Message message = PunishmentCommand.punishmentMessage(sender.user(), Punishment.PunishmentType.NoDevServer);
                messageSender.send(message.format(), message.params());
                return false;
            }
            return true;
        };
    }

    @Mapper(value = "dev", local = true)
    public TypeMapper<String> devServers() {
        return SWCommandUtils.createMapper(s -> s, s -> {
            updateDevServers();
            return devServers.keySet();
        });
    }

    private void updateDevServers() {
        String[] serverFiles = devServerDir.list();

        Map<String, Integer> devServerPorts = new HashMap<>();
        Map<String, Integer> devServerVersions = new HashMap<>();
        if (serverFiles != null) {
            for (String serverFile : serverFiles) {
                String[] server = serverFile.split("\\.");
                int version = Integer.parseInt(server[2]);
                if (version == 0) continue;
                devServerPorts.put(server[0], Integer.parseInt(server[1]));
                devServerVersions.put(server[0], version);
            }
        }

        devServers.entrySet().removeIf(entry -> {
            if (!devServerPorts.containsKey(entry.getKey())) {
                VelocityCore.getProxy().unregisterServer(entry.getValue().getServerInfo());
                return true;
            }
            return false;
        });

        devServerPorts.forEach((username, value) -> {
            SteamwarUser user = SteamwarUser.get(username);
            String name = "Dev " + user.getUserName();
            ((VelocityViaConfig) Via.getConfig()).getVelocityServerProtocols().put(name, ServerVersion.get(devServerVersions.get(username)).getProtocolVersion().getProtocol());

            if (devServers.containsKey(username)) return;
            devServers.put(user.getUserName().toLowerCase(), VelocityCore.getProxy().registerServer(new ServerInfo(name, new InetSocketAddress("127.0.0.1", value))));
        });
    }
}
