package net.viper.status.modules.chat;

import net.md_5.bungee.api.ChatColor;
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.viper.status.ratelimit.GlobalRateLimitFramework;

import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Verwaltet private Nachrichten (/msg, /r) und Social-Spy.
 */
public class PrivateMsgManager {

    private final BlockManager blockManager;
    private final GlobalRateLimitFramework rateLimiter = GlobalRateLimitFramework.getInstance();

    // UUID → letzte PM-Gespr\u00e4chspartner UUID (f\u00fcr /r)
    private final Map<UUID, UUID> lastPartner = new ConcurrentHashMap<>();

    // UUIDs die Social-Spy aktiviert haben
    private final java.util.Set<UUID> spyEnabled =
            java.util.Collections.newSetFromMap(new ConcurrentHashMap<>());

    public PrivateMsgManager(BlockManager blockManager) {
        this.blockManager = blockManager;
    }

    /**
     * Sendet eine private Nachricht von `sender` an `receiver`.
     *
     * @param sender         Der sendende Spieler
     * @param receiver       Der empfangende Spieler
     * @param message        Die Nachricht
     * @param config         Chat-Konfiguration (Formate)
     * @param bypassPermission Permission f\u00fcr Admin-Bypass (kann nicht geblockt werden)
     * @return true wenn erfolgreich gesendet
     */
    public boolean send(ProxiedPlayer sender, ProxiedPlayer receiver,
                        String message, ChatConfig config, String bypassPermission) {

        // Selbst anschreiben verhindern
        if (sender.getUniqueId().equals(receiver.getUniqueId())) {
            sender.sendMessage(color("&cDu kannst dir nicht selbst schreiben."));
            return false;
        }

        // Admin-Bypass: Wenn Sender Admin ist, kann er nicht geblockt werden
        boolean senderIsAdmin = sender.hasPermission(bypassPermission);

        // Block-Check (nur wenn Sender kein Admin)
        if (!senderIsAdmin) {
            if (!blockManager.canReceive(sender.getUniqueId(), receiver.getUniqueId())) {
                sender.sendMessage(color("&cDieser Spieler hat dich blockiert oder du hast ihn blockiert."));
                return false;
            }

            if (config.isPmRateLimitEnabled()) {
                GlobalRateLimitFramework.Result result = rateLimiter.check(
                        "chat.pm",
                        sender.getUniqueId().toString(),
                        new GlobalRateLimitFramework.Rule(
                                true,
                                config.getPmRateLimitWindowMs(),
                                config.getPmRateLimitMaxActions(),
                                config.getPmRateLimitBlockMs()
                        )
                );

                if (result.isBlocked()) {
                    sender.sendMessage(color(config.getPmRateLimitMessage()));
                    return false;
                }
            }
        }

        // Formatierung
        String toSender   = format(config.getPmFormatSender(),   sender.getName(), receiver.getName(), message, true);
        String toReceiver = format(config.getPmFormatReceiver(),  sender.getName(), receiver.getName(), message, false);

        sender.sendMessage(color(toSender));
        receiver.sendMessage(color(toReceiver));

        // Letzte Partner speichern (f\u00fcr /r)
        lastPartner.put(sender.getUniqueId(), receiver.getUniqueId());
        lastPartner.put(receiver.getUniqueId(), sender.getUniqueId());

        // Social Spy
        String spyMsg = format(config.getPmFormatSpy(), sender.getName(), receiver.getName(), message, true);
        broadcastSpy(spyMsg, config.getPmSpyPermission(), sender.getUniqueId(), receiver.getUniqueId());

        return true;
    }

    /**
     * Antwort-Funktion (/r).
     * Sucht den letzten Gespr\u00e4chspartner des Senders.
     */
    public void reply(ProxiedPlayer sender, String message, ChatConfig config, String bypassPermission) {
        UUID partnerUuid = lastPartner.get(sender.getUniqueId());
        if (partnerUuid == null) {
            sender.sendMessage(color("&cDu hast noch keine Nachricht erhalten."));
            return;
        }
        ProxiedPlayer partner = ProxyServer.getInstance().getPlayer(partnerUuid);
        if (partner == null || !partner.isConnected()) {
            sender.sendMessage(color("&cDieser Spieler ist nicht mehr online."));
            return;
        }
        send(sender, partner, message, config, bypassPermission);
    }

    /** Social-Spy umschalten. */
    public boolean toggleSpy(UUID uuid) {
        if (spyEnabled.contains(uuid)) {
            spyEnabled.remove(uuid);
            return false;
        } else {
            spyEnabled.add(uuid);
            return true;
        }
    }

    private void broadcastSpy(String formatted, String spyPermission, UUID... exclude) {
        java.util.Set<UUID> excl = new java.util.HashSet<>(java.util.Arrays.asList(exclude));
        for (ProxiedPlayer p : ProxyServer.getInstance().getPlayers()) {
            if (excl.contains(p.getUniqueId())) continue;
            // Spy muss entweder via Permission aktiv oder manuell aktiviert haben
            boolean hasPerm  = p.hasPermission(spyPermission);
            boolean hasToggle= spyEnabled.contains(p.getUniqueId());
            if (hasPerm || hasToggle) {
                p.sendMessage(color(formatted));
            }
        }
    }

    /**
     * Formatiert eine PM-Nachricht.
     * {sender}   → Name des Absenders
     * {receiver} → Name des Empf\u00e4ngers
     * {player}   → Gespr\u00e4chspartner aus Sicht des jeweiligen Empf\u00e4ngers:
     *              Beim Sender: der Empf\u00e4nger (an wen schreibt er?)
     *              Beim Empf\u00e4nger: der Sender (von wem kommt es?)
     *
     * @param viewerIsSender true wenn der aktuelle Betrachter der Absender ist
     */
    private String format(String template, String sender, String receiver,
                          String message, boolean viewerIsSender) {
        String partner = viewerIsSender ? receiver : sender;
        return template
                .replace("{sender}",   sender)
                .replace("{receiver}", receiver)
                .replace("{player}",   partner)   // Gespr\u00e4chspartner aus Sicht des Betrachters
                .replace("{message}",  message);
    }

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