package net.viper.status.modules.vanish;

import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
import net.md_5.bungee.api.event.PostLoginEvent;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.event.EventHandler;
import net.md_5.bungee.event.EventPriority;
import net.viper.status.module.Module;
import net.viper.status.modules.chat.VanishProvider;

import java.io.*;
import java.util.Collections;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * VanishModule f\u00fcr StatusAPI (BungeeCord)
 *
 * Features:
 *  - /vanish zum Ein-/Ausschalten
 *  - /vanish <Spieler> f\u00fcr Admin-Vanish anderer Spieler
 *  - /vanishlist – zeigt alle aktuell unsichtbaren Spieler
 *  - Vanish-Status wird persistent in vanish.dat gespeichert
 *  - Beim Login wird gespeicherter Status wiederhergestellt
 *  - Volle Integration mit VanishProvider → ChatModule sieht den Status
 *
 * Permission:
 *  - vanish.use  → darf vanishen
 *  - vanish.other → darf andere Spieler vanishen
 *  - vanish.list  → darf /vanishlist nutzen
 *  - chat.admin.bypass → sieht Vanish-Join/Leave-Meldungen im Chat
 */
public class VanishModule implements Module, Listener {

    private static final String PERMISSION      = "chat.admin.bypass";
    private static final String PERMISSION_OTHER = "chat.admin.bypass";
    private static final String PERMISSION_LIST  = "chat.admin.bypass";

    private Plugin plugin;

    // Persistente Vanish-UUIDs (werden in vanish.dat gespeichert)
    private final Set<UUID> persistentVanished =
            Collections.newSetFromMap(new ConcurrentHashMap<>());

    private File dataFile;

    @Override
    public String getName() {
        return "VanishModule";
    }

    @Override
    public void onEnable(Plugin plugin) {
        this.plugin   = plugin;
        this.dataFile = new File(plugin.getDataFolder(), "vanish.dat");

        load();

        plugin.getProxy().getPluginManager().registerListener(plugin, this);
        registerCommands();
    }

    @Override
    public void onDisable(Plugin plugin) {
        save();
        // Alle als sichtbar markieren beim Shutdown (damit beim n\u00e4chsten Start
        // der VanishProvider sauber ist – load() setzt sie beim Login neu)
        for (UUID uuid : persistentVanished) {
            VanishProvider.setVanished(uuid, false);
        }
    }

    // =========================================================
    //  EVENTS
    // =========================================================

    /**
     * Beim Login: Wenn der Spieler persistent gevanisht war, sofort
     * in den VanishProvider eintragen – BEVOR das ChatModule die
     * Join-Nachricht nach 2 Sekunden sendet.
     */
    @EventHandler(priority = EventPriority.LOWEST)
    public void onLogin(PostLoginEvent e) {
        ProxiedPlayer player = e.getPlayer();
        if (persistentVanished.contains(player.getUniqueId())) {
            // Status SOFORT setzen – kein Delay, damit das ChatModule (2s-Task)
            // den Vanish-Status garantiert vorfindet und keine Join-Nachricht sendet.
            VanishProvider.setVanished(player.getUniqueId(), true);

            // Nur die Best\u00e4tigungsnachricht an den Spieler wird verz\u00f6gert,
            // damit der Client bereit ist.
            plugin.getProxy().getScheduler().schedule(plugin, () -> {
                if (player.isConnected()) {
                    player.sendMessage(color("&8[&7Vanish&8] &7Du bist &cUnsichtbar&7."));
                }
            }, 1, java.util.concurrent.TimeUnit.SECONDS);
        }
    }

    @EventHandler
    public void onDisconnect(PlayerDisconnectEvent e) {
        // VanishProvider cleanup – der Eintrag in persistentVanished bleibt
        // erhalten damit der Status beim n\u00e4chsten Login wiederhergestellt wird
        VanishProvider.cleanup(e.getPlayer().getUniqueId());
    }

    // =========================================================
    //  COMMANDS
    // =========================================================

    private void registerCommands() {

        // /vanish [spieler]
        plugin.getProxy().getPluginManager().registerCommand(plugin,
            new Command("vanish", PERMISSION, "v") {
                @Override
                public void execute(CommandSender sender, String[] args) {

                    if (args.length == 0) {
                        // Sich selbst vanishen
                        if (!(sender instanceof ProxiedPlayer)) {
                            sender.sendMessage(color("&cNur Spieler!"));
                            return;
                        }
                        toggleVanish((ProxiedPlayer) sender, (ProxiedPlayer) sender);

                    } else {
                        // Anderen Spieler vanishen
                        if (!sender.hasPermission(PERMISSION_OTHER)) {
                            sender.sendMessage(color("&cDu hast keine Berechtigung f\u00fcr /vanish <Spieler>."));
                            return;
                        }
                        ProxiedPlayer target = ProxyServer.getInstance().getPlayer(args[0]);
                        if (target == null) {
                            sender.sendMessage(color("&cSpieler &f" + args[0] + " &cnicht gefunden."));
                            return;
                        }
                        toggleVanish(sender, target);
                    }
                }
            });

        // /vanishlist
        plugin.getProxy().getPluginManager().registerCommand(plugin,
            new Command("vanishlist", PERMISSION_LIST, "vlist") {
                @Override
                public void execute(CommandSender sender, String[] args) {
                    Set<UUID> vanished = VanishProvider.getVanishedPlayers();
                    if (vanished.isEmpty()) {
                        sender.sendMessage(color("&8[Vanish] &7Keine unsichtbaren Spieler."));
                        return;
                    }
                    sender.sendMessage(color("&8[Vanish] &7Unsichtbare Spieler &8(" + vanished.size() + ")&7:"));
                    for (UUID uuid : vanished) {
                        ProxiedPlayer p = ProxyServer.getInstance().getPlayer(uuid);
                        String name = p != null ? p.getName() : uuid.toString().substring(0, 8) + "...";
                        String online = p != null ? " &8(online)" : " &8(offline/persistent)";
                        sender.sendMessage(color("  &8- &7" + name + online));
                    }
                }
            });
    }

    // =========================================================
    //  VANISH-LOGIK
    // =========================================================

    /**
     * Schaltet den Vanish-Status eines Spielers um.
     *
     * @param executor  Der Befehlsgeber (f\u00fcr Feedback-Nachrichten)
     * @param target    Der betroffene Spieler
     */
    private void toggleVanish(CommandSender executor, ProxiedPlayer target) {
        boolean nowVanished = !VanishProvider.isVanished(target);
        setVanished(target, nowVanished);

        String statusMsg = nowVanished
                ? "&8[&7Vanish&8] &f" + target.getName() + " &7ist jetzt &cUnsichtbar&7."
                : "&8[&7Vanish&8] &f" + target.getName() + " &7ist jetzt &aSichtbar&7.";

        // Feedback an den Ausf\u00fchrenden
        executor.sendMessage(color(statusMsg));

        // Falls jemand anderes gevanisht wurde, auch dem Ziel Bescheid geben
        if (!executor.equals(target)) {
            String selfMsg = nowVanished
                    ? "&8[&7Vanish&8] &7Du wurdest &cUnsichtbar &7gemacht."
                    : "&8[&7Vanish&8] &7Du wurdest &aSichtbar &7gemacht.";
            target.sendMessage(color(selfMsg));
        }

        // Admins mit chat.admin.bypass informieren (au\u00dfer dem Ausf\u00fchrenden)
        for (ProxiedPlayer p : ProxyServer.getInstance().getPlayers()) {
            if (p.equals(executor) || p.equals(target)) continue;
            if (p.hasPermission("chat.admin.bypass")) {
                p.sendMessage(color(statusMsg));
            }
        }
    }

    /**
     * Setzt den Vanish-Status direkt (ohne Toggle).
     * Aktualisiert VanishProvider UND die persistente Liste.
     */
    public void setVanished(ProxiedPlayer player, boolean vanished) {
        VanishProvider.setVanished(player.getUniqueId(), vanished);
        if (vanished) {
            persistentVanished.add(player.getUniqueId());
        } else {
            persistentVanished.remove(player.getUniqueId());
        }
        save();
    }

    /**
     * \u00d6ffentliche API f\u00fcr andere Module.
     */
    public boolean isVanished(ProxiedPlayer player) {
        return VanishProvider.isVanished(player);
    }

    // =========================================================
    //  PERSISTENZ
    // =========================================================

    private void save() {
        try (BufferedWriter bw = new BufferedWriter(
                new OutputStreamWriter(new FileOutputStream(dataFile), "UTF-8"))) {
            for (UUID uuid : persistentVanished) {
                bw.write(uuid.toString());
                bw.newLine();
            }
        } catch (IOException e) {
            plugin.getLogger().warning("[VanishModule] Fehler beim Speichern: " + e.getMessage());
        }
    }

    private void load() {
        persistentVanished.clear();
        if (!dataFile.exists()) return;
        try (BufferedReader br = new BufferedReader(
                new InputStreamReader(new FileInputStream(dataFile), "UTF-8"))) {
            String line;
            while ((line = br.readLine()) != null) {
                line = line.trim();
                if (line.isEmpty()) continue;
                try {
                    persistentVanished.add(UUID.fromString(line));
                } catch (IllegalArgumentException ignored) {}
            }
        } catch (IOException e) {
            plugin.getLogger().warning("[VanishModule] Fehler beim Laden: " + e.getMessage());
        }
    }

    // =========================================================
    //  HILFSMETHODEN
    // =========================================================

    private TextComponent color(String text) {
        return new TextComponent(ChatColor.translateAlternateColorCodes('&', text));
    }
}