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

import com.velocitypowered.api.command.SimpleCommand;
import de.steamwar.messages.Chatter;
import de.steamwar.messages.Message;
import de.steamwar.sql.UserPerm;
import de.steamwar.velocitycore.VelocityCore;
import de.steamwar.velocitycore.discord.DiscordBot;
import lombok.Getter;
import net.kyori.adventure.text.event.ClickEvent;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
import java.util.logging.Level;

public class SWCommand extends AbstractSWCommand<Chatter> {

    static {
        TypeUtils.init();
    }

    private final String name;
    @Getter
    private final UserPerm permission;
    private final String[] aliases;

    private SimpleCommand command;

    private final List<String> defaultHelpMessages = new ArrayList<>();

    protected SWCommand(String command, String... aliases) {
        this(command, null, aliases);
    }

    protected SWCommand(String command, UserPerm permission, String... aliases) {
        super(Chatter.class, command, aliases);
        this.name = command;
        this.permission = permission;
        this.aliases = aliases;
        create = true;
        createAndSafeCommand(command, aliases);
        unregister();
        register();
    }

    public void execute(Chatter sender, String[] args) {
        execute(sender, null, args);
    }

    private boolean create = false;

    @Override
    protected void createAndSafeCommand(String command, String[] aliases) {
        if (!create) return;
        this.command = new SimpleCommand() {

            @Override
            public void execute(Invocation invocation) {
                SWCommand.this.execute(Chatter.of(invocation.source()), invocation.alias(), invocation.arguments());
            }

            @Override
            public List<String> suggest(Invocation invocation) {
                String[] args = invocation.arguments();
                if (args.length == 0) args = new String[]{""};

                return SWCommand.this.tabComplete(Chatter.of(invocation.source()), invocation.alias(), args);
            }

            @Override
            public boolean hasPermission(Invocation invocation) {
                return permission == null || Chatter.of(invocation.source()).user().perms().contains(permission);
            }
        };
    }

    @Override
    public void unregister() {
        if (command == null) return;

        VelocityCore.getProxy().getCommandManager().unregister(name);
        DiscordBot.getCommands().remove(name);
    }

    @Override
    public void register() {
        if (command == null) return;

        VelocityCore.getProxy().getCommandManager().register(VelocityCore.getProxy().getCommandManager().metaBuilder(name).aliases(aliases).plugin(VelocityCore.get()).build(), command);
        DiscordBot.getCommands().put(name, this);
    }

    @Override
    protected void commandSystemError(Chatter sender, CommandFrameworkException e) {
        VelocityCore.getLogger().log(Level.SEVERE, e.getMessage(), e);
        sender.prefixless("COMMAND_SYSTEM_ERROR");
    }

    @Override
    protected void commandSystemWarning(Supplier<String> message) {
        VelocityCore.getLogger().log(Level.WARNING, message);
    }

    public void addDefaultHelpMessage(String message) {
        defaultHelpMessages.add(message);
    }

    @Override
    protected void sendMessage(Chatter sender, String message, Object[] args) {
        sender.system(message, args);
    }

    @Register(noTabComplete = true)
    public void internalHelp(Chatter sender, String... args) {
        try {
            sender.prefixless("COMMAND_HELP_HEAD", name);
            defaultHelpMessages.forEach(sender::prefixless);
        } catch (Exception e) {
            VelocityCore.getLogger().log(Level.WARNING, "Failed to send help message", e);
            return;
        }
        AtomicInteger atomicInteger = new AtomicInteger();
        if (args.length != 0) {
            commandList.forEach(subCommand -> {
                List<String> tabCompletes = subCommand.tabComplete(sender, args);
                if (tabCompletes == null || tabCompletes.isEmpty()) {
                    atomicInteger.incrementAndGet();
                    return;
                }
                boolean hasTabCompletes = tabCompletes.stream()
                        .anyMatch(s -> s.toLowerCase().startsWith(args[args.length - 1].toLowerCase()));
                if (hasTabCompletes) {
                    send(sender, subCommand);
                } else {
                    atomicInteger.incrementAndGet();
                }
            });
        }
        if (args.length == 0 || atomicInteger.get() == commandList.size()) {
            commandList.forEach(subCommand -> {
                if (subCommand.validator == null || subCommand.validator.validate(sender, sender, (s, args1) -> {
                })) {
                    send(sender, subCommand);
                }
            });
        }
    }

    private void send(Chatter chatter, SubCommand<Chatter> subCommand) {
        try {
            for (String s : subCommand.description) {
                String hover = "§8/§e" + name + " " + String.join(" ", subCommand.subCommand);
                chatter.prefixless(s, new Message("PLAIN_STRING", hover), ClickEvent.suggestCommand("/" + name + " " + String.join(" ", subCommand.subCommand)));
            }
        } catch (Exception e) {
            VelocityCore.getLogger().log(Level.WARNING, "Failed to send description of registered method '%s' with description '%s'".formatted(subCommand.method, Arrays.toString(subCommand.description)), e);
        }
    }
}
