package de.viper.survivalplus.commands;

import de.viper.survivalplus.SurvivalPlus;
import de.viper.survivalplus.Manager.Warp;
import de.viper.survivalplus.Manager.WarpManager;
import de.viper.survivalplus.fun.FunChallenge;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.UUID;

public class SurvivalPlusTabCompleter implements TabCompleter {

    private static final List<String> SP_SUBCOMMANDS = List.of(
            "help", "reload", "info", "share", "shareconfirm", "sharecancel", "cb",
            "lock", "unlock", "friendadd", "friendremove"
    );
    private static final List<String> SP_CB_SUBCOMMANDS = List.of("add", "remove", "list");
    private static final List<String> FRIEND_SUBCOMMANDS = List.of("add", "accept", "deny", "list", "del", "confirm", "tp");
    private static final List<String> CLAIM_SUBCOMMANDS = List.of("mark", "unclaim", "del", "delete", "trust", "untrust", "info", "kick", "ban", "unban");
    private static final List<String> SPLOCK_SUBCOMMANDS = List.of("lock", "unlock", "friendadd", "friendremove");
    private static final List<String> SHOP_SUBCOMMANDS = List.of("gui", "add");
    private static final List<String> NICK_SUBCOMMANDS = List.of("off", "remove", "reset");
    private static final List<String> GAMEMODE_SUBCOMMANDS = List.of("0", "1", "2", "3", "survival", "creative", "adventure", "spectator");

    private final SurvivalPlus plugin;

    public SurvivalPlusTabCompleter(SurvivalPlus plugin) {
        this.plugin = plugin;
    }

    @Override
    public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
        String cmd = command.getName().toLowerCase(Locale.ROOT);
        if (args.length == 0) {
            return Collections.emptyList();
        }

        switch (cmd) {
            case "sp":
                return completeSp(sender, args);
            case "friend":
                return completeFriend(sender, args);
            case "claim":
                return completeClaim(sender, args);
            case "splock":
                return completeSplock(sender, args);
            case "shop":
                return completeShop(sender, args);
            case "nick":
                return filterPrefix(NICK_SUBCOMMANDS, args[0]);
            case "gm":
                return completeGamemode(sender, args);
            case "tp":
            case "tphere":
            case "tpa":
            case "trade":
            case "tradeaccept":
            case "report":
            case "showreport":
            case "clearreport":
            case "block":
            case "unblock":
            case "head":
            case "freeze":
                return completePlayerArg(sender, args);
            case "heal":
            case "inv":
            case "ec":
            case "ride":
                return completeOptionalPlayerArg(sender, args);
            case "tploot":
                return completeTploot(args);
            case "startchallenge":
                return completeChallenges(args);
            case "delwarp":
                return completePlayerWarpNames(sender, args);
            case "home":
            case "delhome":
                return completePlayerHomeNames(sender, args);
            default:
                return Collections.emptyList();
        }
    }

    private List<String> completeSp(CommandSender sender, String[] args) {
        if (args.length == 1) {
            return filterPrefix(SP_SUBCOMMANDS, args[0]);
        }
        if (args.length == 2 && args[0].equalsIgnoreCase("cb")) {
            return filterPrefix(SP_CB_SUBCOMMANDS, args[1]);
        }
        if (args.length == 3 && args[0].equalsIgnoreCase("cb") && args[1].equalsIgnoreCase("remove")) {
            return filterPrefix(getBlockedCommands(), args[2]);
        }
        if (args.length == 2 && (args[0].equalsIgnoreCase("friendadd") || args[0].equalsIgnoreCase("friendremove"))) {
            return filterPrefix(getOnlinePlayerNames(sender), args[1]);
        }
        return Collections.emptyList();
    }

    private List<String> completeFriend(CommandSender sender, String[] args) {
        if (args.length == 1) {
            return filterPrefix(FRIEND_SUBCOMMANDS, args[0]);
        }
        if (args.length == 2) {
            String sub = args[0].toLowerCase(Locale.ROOT);
            if (sub.equals("add") || sub.equals("accept") || sub.equals("deny") || sub.equals("tp")) {
                return filterPrefix(getOnlinePlayerNames(sender), args[1]);
            }
            if (sub.equals("del") || sub.equals("confirm")) {
                return filterPrefix(getFriendNames(sender), args[1]);
            }
        }
        return Collections.emptyList();
    }

    private List<String> completeClaim(CommandSender sender, String[] args) {
        if (args.length == 1) {
            return filterPrefix(CLAIM_SUBCOMMANDS, args[0]);
        }
        if (args.length == 2) {
            String sub = args[0].toLowerCase(Locale.ROOT);
            if (sub.equals("mark")) {
                return filterPrefix(List.of("1", "2"), args[1]);
            }
            if (sub.equals("trust") || sub.equals("untrust") || sub.equals("kick") || sub.equals("ban") || sub.equals("unban")
                    || sub.equals("unclaim") || sub.equals("del") || sub.equals("delete")) {
                return filterPrefix(getOnlinePlayerNames(sender), args[1]);
            }
        }
        return Collections.emptyList();
    }

    private List<String> completeSplock(CommandSender sender, String[] args) {
        if (args.length == 1) {
            return filterPrefix(SPLOCK_SUBCOMMANDS, args[0]);
        }
        if (args.length == 2) {
            String sub = args[0].toLowerCase(Locale.ROOT);
            if (sub.equals("friendadd") || sub.equals("friendremove")) {
                return filterPrefix(getOnlinePlayerNames(sender), args[1]);
            }
        }
        return Collections.emptyList();
    }

    private List<String> completeShop(CommandSender sender, String[] args) {
        if (args.length == 1) {
            return filterPrefix(SHOP_SUBCOMMANDS, args[0]);
        }
        if (args.length == 2 && args[0].equalsIgnoreCase("add")) {
            String prefix = args[1];
            if (prefix.length() < 2) {
                return Collections.emptyList();
            }
            return getMaterialNames(prefix);
        }
        return Collections.emptyList();
    }

    private List<String> completeGamemode(CommandSender sender, String[] args) {
        if (args.length == 1) {
            return filterPrefix(GAMEMODE_SUBCOMMANDS, args[0]);
        }
        if (args.length == 2) {
            return filterPrefix(getOnlinePlayerNames(sender), args[1]);
        }
        return Collections.emptyList();
    }

    private List<String> completePlayerArg(CommandSender sender, String[] args) {
        if (args.length == 1) {
            return filterPrefix(getOnlinePlayerNames(sender), args[0]);
        }
        return Collections.emptyList();
    }

    private List<String> completeOptionalPlayerArg(CommandSender sender, String[] args) {
        if (args.length == 1) {
            return filterPrefix(getOnlinePlayerNames(sender), args[0]);
        }
        return Collections.emptyList();
    }

    private List<String> completeTploot(String[] args) {
        if (args.length == 1) {
            return filterPrefix(getWorldNames(), args[0]);
        }
        return Collections.emptyList();
    }

    private List<String> completeChallenges(String[] args) {
        if (args.length == 1) {
            return filterPrefix(getChallengeNames(), args[0]);
        }
        return Collections.emptyList();
    }

    private List<String> completePlayerHomeNames(CommandSender sender, String[] args) {
        if (args.length == 1) {
            return filterPrefix(getHomeNames(sender), args[0]);
        }
        return Collections.emptyList();
    }

    private List<String> completePlayerWarpNames(CommandSender sender, String[] args) {
        if (args.length == 1) {
            return filterPrefix(getWarpNames(sender), args[0]);
        }
        return Collections.emptyList();
    }

    private List<String> getOnlinePlayerNames(CommandSender sender) {
        List<String> names = new ArrayList<>();
        for (Player player : Bukkit.getOnlinePlayers()) {
            if (!player.getName().equalsIgnoreCase(sender.getName())) {
                names.add(player.getName());
            }
        }
        return names;
    }

    private List<String> getBlockedCommands() {
        FileConfiguration blocked = plugin.getBlockedCommandsConfig();
        if (blocked == null) {
            return Collections.emptyList();
        }
        List<String> commands = blocked.getStringList("blocked-commands");
        return commands == null ? Collections.emptyList() : commands;
    }

    private List<String> getFriendNames(CommandSender sender) {
        if (!(sender instanceof Player player)) {
            return Collections.emptyList();
        }
        FileConfiguration friends = plugin.getFriendsConfig();
        if (friends == null) {
            return Collections.emptyList();
        }
        List<String> friendIds = friends.getStringList(player.getUniqueId().toString() + ".friends");
        if (friendIds == null || friendIds.isEmpty()) {
            return Collections.emptyList();
        }
        List<String> names = new ArrayList<>();
        for (String id : friendIds) {
            try {
                UUID uuid = UUID.fromString(id);
                OfflinePlayer offline = Bukkit.getOfflinePlayer(uuid);
                if (offline.getName() != null) {
                    names.add(offline.getName());
                    continue;
                }
                String storedName = friends.getString(id + ".name");
                if (storedName != null && !storedName.isEmpty()) {
                    names.add(storedName);
                }
            } catch (IllegalArgumentException ignored) {
            }
        }
        return names;
    }

    private List<String> getHomeNames(CommandSender sender) {
        if (!(sender instanceof Player player)) {
            return Collections.emptyList();
        }
        FileConfiguration homes = plugin.getHomesConfig();
        if (homes == null) {
            return Collections.emptyList();
        }
        String path = "homes." + player.getUniqueId();
        if (homes.getConfigurationSection(path) == null) {
            return Collections.emptyList();
        }
        return new ArrayList<>(homes.getConfigurationSection(path).getKeys(false));
    }

    private List<String> getWarpNames(CommandSender sender) {
        if (!(sender instanceof Player player)) {
            return Collections.emptyList();
        }
        WarpManager warpManager = plugin.getWarpManager();
        if (warpManager == null) {
            return Collections.emptyList();
        }
        List<String> warps = new ArrayList<>();
        for (Warp warp : warpManager.getWarps().values()) {
            if (warp.getOwner().equalsIgnoreCase(player.getName())) {
                warps.add(warp.getName());
            }
        }
        return warps;
    }

    private List<String> getChallengeNames() {
        if (plugin.getFunChallengeManager() == null) {
            return Collections.emptyList();
        }
        List<String> names = new ArrayList<>();
        for (FunChallenge challenge : plugin.getFunChallengeManager().getChallenges()) {
            names.add(challenge.getName());
        }
        return names;
    }

    private List<String> getWorldNames() {
        List<String> names = new ArrayList<>();
        for (World world : Bukkit.getWorlds()) {
            names.add(world.getName());
        }
        return names;
    }

    private List<String> getMaterialNames(String prefix) {
        List<String> names = new ArrayList<>();
        String normalized = prefix == null ? "" : prefix.toUpperCase(Locale.ROOT);
        for (Material material : Material.values()) {
            if (!material.isItem() || material == Material.AIR) {
                continue;
            }
            String name = material.name();
            if (name.startsWith(normalized)) {
                names.add(name);
            }
        }
        Collections.sort(names);
        if (names.size() > 25) {
            return new ArrayList<>(names.subList(0, 25));
        }
        return names;
    }

    private List<String> filterPrefix(Collection<String> options, String prefix) {
        if (options == null || options.isEmpty()) {
            return Collections.emptyList();
        }
        String normalized = prefix == null ? "" : prefix.toLowerCase(Locale.ROOT);
        List<String> results = new ArrayList<>();
        Set<String> dedup = new HashSet<>();
        for (String option : options) {
            if (option == null) {
                continue;
            }
            String value = option.toString();
            if (value.toLowerCase(Locale.ROOT).startsWith(normalized)) {
                if (dedup.add(value)) {
                    results.add(value);
                }
            }
        }
        Collections.sort(results);
        return results;
    }
}
