package net.viper.status.modules.chat;

import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.config.Configuration;
import net.md_5.bungee.config.ConfigurationProvider;
import net.md_5.bungee.config.YamlConfiguration;

import java.io.*;
import java.nio.file.Files;
import java.util.*;

/**
 * L\u00e4dt und verwaltet die chat.yml Konfiguration.
 *
 * Fix #8: Rate-Limit-Werte aus anti-spam werden nicht mehr durch nachfolgende
 * Berechnungen \u00fcberschrieben. Der rate-limit.chat-Block hat jetzt Vorrang.
 * Die Reihenfolge ist: erst rate-limit.chat einlesen, dann ggf. durch anti-spam
 * als Fallback erg\u00e4nzen, nicht umgekehrt.
 */
public class ChatConfig {

    private final Plugin plugin;
    private Configuration config;

    private final Map<String, ChatChannel> channels = new LinkedHashMap<>();
    private String defaultChannel;

    private String helpopFormat, helpopPermission, helpopConfirm, helpopDiscordWebhook, helpopTelegramChatId;
    private int helpopCooldown;

    private String broadcastFormat, broadcastPermission;

    private boolean pmEnabled;
    private String pmFormatSender, pmFormatReceiver, pmFormatSpy, pmSpyPermission, pmRateLimitMessage;
    private boolean pmRateLimitEnabled;
    private long pmRateLimitWindowMs;
    private int pmRateLimitMaxActions;
    private long pmRateLimitBlockMs;

    private int defaultMuteDuration;
    private String mutedMessage;

    private boolean emojiEnabled, emojiBedrockSupport;
    private final Map<String, String> emojiMappings = new LinkedHashMap<>();

    private boolean discordEnabled;
    private String discordBotToken, discordGuildId, discordFromFormat, discordAdminChannelId, discordEmbedColor;
    private int discordPollInterval;

    private boolean telegramEnabled;
    private String telegramBotToken, telegramFromFormat, telegramAdminChatId;
    private int telegramPollInterval, telegramChatTopicId, telegramAdminTopicId;

    private boolean linkingEnabled;
    private String linkDiscordMessage, linkTelegramMessage, linkSuccessDiscord, linkSuccessTelegram;
    private String linkBotSuccessDiscord, linkBotSuccessTelegram, linkedDiscordFormat, linkedTelegramFormat;
    private int telegramAdminThreadId;

    private String adminBypassPermission, adminNotifyPermission;

    private boolean chatlogEnabled;
    private int chatlogRetentionDays;

    private final Map<String, String> serverColors = new LinkedHashMap<>();
    private final Map<String, String> serverDisplayNames = new LinkedHashMap<>();
    private String serverColorDefault;

    private boolean reportsEnabled, reportWebhookEnabled;
    private String reportConfirm, reportPermission, reportClosePermission, reportViewPermission;
    private String reportDiscordWebhook, reportTelegramChatId;
    private int reportCooldown;

    private ChatFilter.ChatFilterConfig filterConfig = new ChatFilter.ChatFilterConfig();

    private boolean mentionsEnabled, mentionsAllowToggle;
    private String mentionsHighlightColor, mentionsSound, mentionsNotifyPrefix;

    private int historyMaxLines, historyDefaultLines;

    private boolean joinLeaveEnabled, vanishShowToAdmins;
    private String joinFormat, leaveFormat, vanishJoinFormat, vanishLeaveFormat;
    private String joinLeaveDiscordWebhook, joinLeaveTelegramChatId;
    private int joinLeaveTelegramThreadId;

    public ChatConfig(Plugin plugin) { this.plugin = plugin; }

    public void load() {
        File file = new File(plugin.getDataFolder(), "chat.yml");
        if (!file.exists()) {
            plugin.getDataFolder().mkdirs();
            InputStream in = plugin.getResourceAsStream("chat.yml");
            if (in != null) {
                try { Files.copy(in, file.toPath()); }
                catch (IOException e) { plugin.getLogger().severe("[ChatModule] Konnte chat.yml nicht erstellen: " + e.getMessage()); }
            } else {
                plugin.getLogger().warning("[ChatModule] chat.yml nicht in JAR, erstelle leere Datei.");
                try { file.createNewFile(); } catch (IOException ignored) {}
            }
        }
        try { config = ConfigurationProvider.getProvider(YamlConfiguration.class).load(file); }
        catch (IOException e) {
            plugin.getLogger().severe("[ChatModule] Fehler beim Laden der chat.yml: " + e.getMessage());
            config = new Configuration();
        }
        parseConfig();
        plugin.getLogger().fine("[ChatModule] " + channels.size() + " Kan\u00e4le geladen.");
    }

    private void parseConfig() {
        defaultChannel = config.getString("default-channel", "global");

        // --- Kan\u00e4le ---
        channels.clear();
        Configuration chSection = config.getSection("channels");
        if (chSection != null) {
            for (String id : chSection.getKeys()) {
                Configuration ch = chSection.getSection(id);
                if (ch == null) continue;
                channels.put(id.toLowerCase(), new ChatChannel(
                        id.toLowerCase(),
                        ch.getString("name", id),
                        ch.getString("symbol", id.substring(0, 1).toUpperCase()),
                        ch.getString("permission", ""),
                        ch.getString("color", "&f"),
                        ch.getString("format", "&8[&7{server}&8] {prefix}&r{player}{suffix}&8: &f{message}"),
                        ch.getBoolean("local-only", false),
                        ch.getString("discord-webhook", ""),
                        ch.getString("discord-channel-id", ""),
                        ch.getString("telegram-chat-id", ""),
                        ch.getInt("telegram-thread-id", 0),
                        ch.getBoolean("use-admin-bridge", false)
                ));
            }
        }
        if (!channels.containsKey("global")) {
            channels.put("global", new ChatChannel("global", "Global", "G", "", "&a",
                    "&8[&a{server}&8] {prefix}&r{player}{suffix}&8: &f{message}", false, "", "", "", 0, false));
        }

        // --- HelpOp ---
        Configuration ho = config.getSection("helpop");
        if (ho != null) {
            helpopFormat         = ho.getString("format", "&8[&eHELPOP&8] &f{player}&8@&7{server}&8: &e{message}");
            helpopPermission     = ho.getString("receive-permission", "chat.helpop.receive");
            helpopCooldown       = ho.getInt("cooldown", 30);
            helpopConfirm        = ho.getString("confirm-message", "&aHilferuf gesendet!");
            helpopDiscordWebhook = ho.getString("discord-webhook", "");
            helpopTelegramChatId = ho.getString("telegram-chat-id", "");
        } else {
            helpopFormat = "&8[&eHELPOP&8] &f{player}&8@&7{server}&8: &e{message}";
            helpopPermission = "chat.helpop.receive"; helpopCooldown = 30;
            helpopConfirm = "&aHilferuf gesendet!"; helpopDiscordWebhook = ""; helpopTelegramChatId = "";
        }

        // --- Broadcast ---
        Configuration bc = config.getSection("broadcast");
        broadcastFormat     = bc != null ? bc.getString("format", "&c[&6Broadcast&c] &e{message}") : "&c[&6Broadcast&c] &e{message}";
        broadcastPermission = bc != null ? bc.getString("permission", "chat.broadcast") : "chat.broadcast";

        // --- Private Messages ---
        Configuration pm = config.getSection("private-messages");
        pmEnabled        = pm == null || pm.getBoolean("enabled", true);
        pmFormatSender   = pm != null ? pm.getString("format-sender",    "&8[&7Du &8→ &b{player}&8] &f{message}") : "&8[&7Du &8→ &b{player}&8] &f{message}";
        pmFormatReceiver = pm != null ? pm.getString("format-receiver",  "&8[&b{player} &8→ &7Dir&8] &f{message}") : "&8[&b{player} &8→ &7Dir&8] &f{message}";
        pmFormatSpy      = pm != null ? pm.getString("format-social-spy","&8[&dSPY &7{sender} &8→ &7{receiver}&8] &f{message}") : "&8[&dSPY &7{sender} &8→ &7{receiver}&8] &f{message}";
        pmSpyPermission  = pm != null ? pm.getString("social-spy-permission", "chat.socialspy") : "chat.socialspy";

        // --- Mute ---
        Configuration mu = config.getSection("mute");
        defaultMuteDuration = mu != null ? mu.getInt("default-duration-minutes", 60) : 60;
        mutedMessage        = mu != null ? mu.getString("muted-message", "&cDu bist stummgeschaltet. Noch: &f{time}") : "&cDu bist stummgeschaltet. Noch: &f{time}";

        // --- Emoji ---
        Configuration em = config.getSection("emoji");
        if (em != null) {
            emojiEnabled        = em.getBoolean("enabled", true);
            emojiBedrockSupport = em.getBoolean("bedrock-support", true);
            emojiMappings.clear();
            Configuration map = em.getSection("mappings");
            if (map != null) { for (String key : map.getKeys()) emojiMappings.put(key, map.getString(key, key)); }
        } else { emojiEnabled = true; emojiBedrockSupport = true; }

        // --- Discord ---
        Configuration dc = config.getSection("discord");
        if (dc != null) {
            discordEnabled        = dc.getBoolean("enabled", false);
            discordBotToken       = dc.getString("bot-token", "");
            discordGuildId        = dc.getString("guild-id", "");
            discordPollInterval   = dc.getInt("poll-interval", 3);
            discordFromFormat     = dc.getString("from-discord-format", "&9[Discord] &b{user}&8: &f{message}");
            discordAdminChannelId = dc.getString("admin-channel-id", "");
            discordEmbedColor     = dc.getString("embed-color", "5865F2");
        } else { discordEnabled = false; discordBotToken = ""; discordGuildId = ""; discordPollInterval = 3; discordFromFormat = "&9[Discord] &b{user}&8: &f{message}"; discordAdminChannelId = ""; discordEmbedColor = "5865F2"; }

        // --- Telegram ---
        Configuration tg = config.getSection("telegram");
        if (tg != null) {
            telegramEnabled      = tg.getBoolean("enabled", false);
            telegramBotToken     = tg.getString("bot-token", "");
            telegramPollInterval = tg.getInt("poll-interval", 3);
            telegramFromFormat   = tg.getString("from-telegram-format", "&3[Telegram] &b{user}&8: &f{message}");
            telegramAdminChatId  = tg.getString("admin-chat-id", "");
            telegramChatTopicId  = tg.getInt("chat-topic-id", 0);
            telegramAdminTopicId = tg.getInt("admin-topic-id", 0);
        } else { telegramEnabled = false; telegramBotToken = ""; telegramPollInterval = 3; telegramFromFormat = "&3[Telegram] &b{user}&8: &f{message}"; telegramAdminChatId = ""; telegramChatTopicId = 0; telegramAdminTopicId = 0; }

        // --- Account-Linking ---
        Configuration al = config.getSection("account-linking");
        linkingEnabled         = al == null || al.getBoolean("enabled", true);
        linkDiscordMessage     = al != null ? al.getString("discord-link-message",  "&aCode: &f{token}") : "&aCode: &f{token}";
        linkTelegramMessage    = al != null ? al.getString("telegram-link-message", "&aCode: &f{token}") : "&aCode: &f{token}";
        linkSuccessDiscord     = al != null ? al.getString("success-discord",   "&aDiscord verkn\u00fcpft!") : "&aDiscord verkn\u00fcpft!";
        linkSuccessTelegram    = al != null ? al.getString("success-telegram",  "&aTelegram verkn\u00fcpft!") : "&aTelegram verkn\u00fcpft!";
        linkBotSuccessDiscord  = al != null ? al.getString("bot-success-discord",  "✅ Verkn\u00fcpft: {player}") : "✅ Verkn\u00fcpft: {player}";
        linkBotSuccessTelegram = al != null ? al.getString("bot-success-telegram", "✅ Verkn\u00fcpft: {player}") : "✅ Verkn\u00fcpft: {player}";
        linkedDiscordFormat    = al != null ? al.getString("linked-discord-format",  "&9[&bDiscord&9] &f{player} &8(&7{user}&8)&8: &f{message}") : "&9[&bDiscord&9] &f{player} &8(&7{user}&8)&8: &f{message}";
        linkedTelegramFormat   = al != null ? al.getString("linked-telegram-format", "&3[&bTelegram&3] &f{player} &8(&7{user}&8)&8: &f{message}") : "&3[&bTelegram&3] &f{player} &8(&7{user}&8)&8: &f{message}";

        // --- Chat-Filter ---
        filterConfig = new ChatFilter.ChatFilterConfig();
        Configuration cf = config.getSection("chat-filter");
        if (cf != null) {
            Configuration spam = cf.getSection("anti-spam");
            if (spam != null) {
                filterConfig.antiSpamEnabled = spam.getBoolean("enabled", true);
                filterConfig.spamCooldownMs  = spam.getInt("cooldown-ms", 1500);
                filterConfig.spamMaxMessages = spam.getInt("max-messages", 3);
                filterConfig.spamMessage     = spam.getString("message", "&cNicht so schnell!");
                // FIX #8: Fallback-Werte aus anti-spam werden NUR gesetzt wenn rate-limit.chat nicht
                // konfiguriert ist. Wir setzen die Werte hier als Vorbelegung und \u00fcberschreiben sie
                // unten mit dem rate-limit.chat-Block wenn vorhanden.
                filterConfig.globalRateLimitWindowMs    = Math.max(500L, filterConfig.spamCooldownMs);
                filterConfig.globalRateLimitMaxActions  = Math.max(1, filterConfig.spamMaxMessages);
                filterConfig.globalRateLimitBlockMs     = Math.max(2000L, filterConfig.spamCooldownMs * 4L);
            }
            Configuration dup = cf.getSection("duplicate-check");
            if (dup != null) {
                filterConfig.duplicateCheckEnabled = dup.getBoolean("enabled", true);
                filterConfig.duplicateMessage      = dup.getString("message", "&cKeine identischen Nachrichten.");
            }
            Configuration bl = cf.getSection("blacklist");
            if (bl != null) {
                filterConfig.blacklistEnabled = bl.getBoolean("enabled", true);
                filterConfig.blacklistWords.clear();
                loadFilterWords(filterConfig.blacklistWords);
                try {
                    java.util.List<?> wordList = bl.getList("words");
                    if (wordList != null) {
                        for (Object o : wordList) {
                            if (o != null && !o.toString().trim().isEmpty()) {
                                String w = o.toString().trim();
                                if (!filterConfig.blacklistWords.contains(w)) filterConfig.blacklistWords.add(w);
                            }
                        }
                    }
                } catch (Exception ignored) {}
            }
            Configuration caps = cf.getSection("caps-filter");
            if (caps != null) {
                filterConfig.capsFilterEnabled = caps.getBoolean("enabled", true);
                filterConfig.capsMinLength     = caps.getInt("min-length", 6);
                filterConfig.capsMaxPercent    = caps.getInt("max-percent", 70);
            }
            Configuration antiAd = cf.getSection("anti-ad");
            if (antiAd != null) {
                filterConfig.antiAdEnabled = antiAd.getBoolean("enabled", true);
                filterConfig.antiAdMessage = antiAd.getString("message", "&cWerbung ist nicht erlaubt!");
                java.util.List<?> wl = antiAd.getList("whitelist");
                if (wl != null) { filterConfig.antiAdWhitelist.clear(); for (Object o : wl) if (o != null) filterConfig.antiAdWhitelist.add(o.toString()); }
                java.util.List<?> tlds = antiAd.getList("blocked-tlds");
                if (tlds != null) { filterConfig.antiAdBlockedTlds.clear(); for (Object o : tlds) if (o != null) filterConfig.antiAdBlockedTlds.add(o.toString()); }
            }
        }

        // --- Rate-Limit (FIX #8: dieser Block setzt die endg\u00fcltigen Werte, hat Vorrang) ---
        pmRateLimitEnabled    = true;
        pmRateLimitWindowMs   = 5000L;
        pmRateLimitMaxActions = 4;
        pmRateLimitBlockMs    = 10000L;
        pmRateLimitMessage    = "&cDu sendest zu viele private Nachrichten. Bitte warte kurz.";

        Configuration rl = config.getSection("rate-limit");
        if (rl != null) {
            Configuration rlChat = rl.getSection("chat");
            if (rlChat != null) {
                // FIX #8: rate-limit.chat \u00fcberschreibt die anti-spam-Fallbacks vollst\u00e4ndig
                filterConfig.globalRateLimitEnabled    = rlChat.getBoolean("enabled", true);
                filterConfig.globalRateLimitWindowMs   = rlChat.getLong("window-ms",   filterConfig.globalRateLimitWindowMs);
                filterConfig.globalRateLimitMaxActions = rlChat.getInt("max-actions",  filterConfig.globalRateLimitMaxActions);
                filterConfig.globalRateLimitBlockMs    = rlChat.getLong("block-ms",    filterConfig.globalRateLimitBlockMs);
                filterConfig.spamMessage               = rlChat.getString("message",   filterConfig.spamMessage);
            }
            Configuration rlPm = rl.getSection("private-messages");
            if (rlPm != null) {
                pmRateLimitEnabled    = rlPm.getBoolean("enabled",    pmRateLimitEnabled);
                pmRateLimitWindowMs   = rlPm.getLong("window-ms",    pmRateLimitWindowMs);
                pmRateLimitMaxActions = rlPm.getInt("max-actions",   pmRateLimitMaxActions);
                pmRateLimitBlockMs    = rlPm.getLong("block-ms",     pmRateLimitBlockMs);
                pmRateLimitMessage    = rlPm.getString("message",    pmRateLimitMessage);
            }
        }

        // --- Mentions ---
        Configuration mn = config.getSection("mentions");
        mentionsEnabled        = mn == null || mn.getBoolean("enabled", true);
        mentionsHighlightColor = mn != null ? mn.getString("highlight-color", "&e&l") : "&e&l";
        mentionsSound          = mn != null ? mn.getString("sound", "ENTITY_EXPERIENCE_ORB_PICKUP") : "ENTITY_EXPERIENCE_ORB_PICKUP";
        mentionsAllowToggle    = mn == null || mn.getBoolean("allow-toggle", true);
        mentionsNotifyPrefix   = mn != null ? mn.getString("notify-prefix", "&e&l[Mention] &r") : "&e&l[Mention] &r";

        // --- Chat-History ---
        Configuration ch = config.getSection("chat-history");
        historyMaxLines     = ch != null ? ch.getInt("max-lines", 50) : 50;
        historyDefaultLines = ch != null ? ch.getInt("default-lines", 10) : 10;

        // --- Admin ---
        Configuration adm = config.getSection("admin");
        adminBypassPermission = adm != null ? adm.getString("bypass-permission", "chat.admin.bypass") : "chat.admin.bypass";
        adminNotifyPermission = adm != null ? adm.getString("notify-permission", "chat.admin.notify") : "chat.admin.notify";

        // --- Server-Farben ---
        serverColors.clear(); serverDisplayNames.clear();
        Configuration sc = config.getSection("server-colors");
        if (sc != null) {
            serverColorDefault = sc.getString("default", "&7");
            for (String key : sc.getKeys()) {
                if (key.equals("default")) continue;
                Configuration sub = sc.getSection(key);
                if (sub != null) {
                    serverColors.put(key.toLowerCase(), sub.getString("color", "&7"));
                    String display = sub.getString("display", "");
                    if (!display.isEmpty()) serverDisplayNames.put(key.toLowerCase(), display);
                } else {
                    serverColors.put(key.toLowerCase(), sc.getString(key, "&7"));
                }
            }
        } else { serverColorDefault = "&7"; }

        // --- Chatlog ---
        Configuration cl = config.getSection("chatlog");
        chatlogEnabled       = cl == null || cl.getBoolean("enabled", true);
        int raw = cl != null ? cl.getInt("retention-days", 7) : 7;
        chatlogRetentionDays = (raw == 14) ? 14 : 7;

        // --- Reports ---
        Configuration rp = config.getSection("reports");
        if (rp != null) {
            reportsEnabled        = rp.getBoolean("enabled", true);
            reportWebhookEnabled  = rp.getBoolean("webhook-enabled", false);
            reportConfirm         = rp.getString("confirm-message", "&aDein Report &8({id}) &awurde eingereicht. Danke!");
            reportPermission      = rp.getString("report-permission", "");
            reportClosePermission = rp.getString("close-permission", "chat.admin.bypass");
            reportViewPermission  = rp.getString("view-permission",  "chat.admin.bypass");
            reportCooldown        = rp.getInt("cooldown", 60);
            reportDiscordWebhook  = rp.getString("discord-webhook", "");
            reportTelegramChatId  = rp.getString("telegram-chat-id", "");
        } else {
            reportsEnabled = true; reportWebhookEnabled = false;
            reportConfirm = "&aDein Report &8({id}) &awurde eingereicht. Danke!";
            reportPermission = ""; reportClosePermission = "chat.admin.bypass"; reportViewPermission = "chat.admin.bypass";
            reportCooldown = 60; reportDiscordWebhook = ""; reportTelegramChatId = "";
        }

        // --- Join / Leave ---
        Configuration jl = config.getSection("join-leave");
        if (jl != null) {
            joinLeaveEnabled          = jl.getBoolean("enabled", true);
            joinFormat                = jl.getString("join-format",  "&8[&a+&8] {prefix}&a{player}&r &7hat das Netzwerk betreten.");
            leaveFormat               = jl.getString("leave-format", "&8[&c-&8] {prefix}&c{player}&r &7hat das Netzwerk verlassen.");
            vanishShowToAdmins        = jl.getBoolean("vanish-show-to-admins", true);
            vanishJoinFormat          = jl.getString("vanish-join-format",  "&8[&7+&8] &8{player} &7hat das Netzwerk betreten. &8(Vanish)");
            vanishLeaveFormat         = jl.getString("vanish-leave-format", "&8[&7-&8] &8{player} &7hat das Netzwerk verlassen. &8(Vanish)");
            joinLeaveDiscordWebhook   = jl.getString("discord-webhook", "");
            joinLeaveTelegramChatId   = jl.getString("telegram-chat-id", "");
            joinLeaveTelegramThreadId = jl.getInt("telegram-thread-id", 0);
        } else {
            joinLeaveEnabled = true;
            joinFormat = "&8[&a+&8] {prefix}&a{player}&r &7hat das Netzwerk betreten.";
            leaveFormat = "&8[&c-&8] {prefix}&c{player}&r &7hat das Netzwerk verlassen.";
            vanishShowToAdmins = true;
            vanishJoinFormat = "&8[&7+&8] &8{player} &7hat das Netzwerk betreten. &8(Vanish)";
            vanishLeaveFormat = "&8[&7-&8] &8{player} &7hat das Netzwerk verlassen. &8(Vanish)";
            joinLeaveDiscordWebhook = ""; joinLeaveTelegramChatId = ""; joinLeaveTelegramThreadId = 0;
        }
    }

    private void loadFilterWords(java.util.List<String> target) {
        File filterFile = new File(plugin.getDataFolder(), "filter.yml");
        if (!filterFile.exists()) {
            try {
                plugin.getDataFolder().mkdirs();
                try (java.io.FileWriter fw = new java.io.FileWriter(filterFile)) {
                    fw.write("# StatusAPI - Wort-Blacklist\n# words:\n#   - beispielwort\nwords:\n");
                }
                plugin.getLogger().fine("[ChatModule] filter.yml erstellt.");
            } catch (IOException e) { plugin.getLogger().warning("[ChatModule] Konnte filter.yml nicht erstellen: " + e.getMessage()); }
            return;
        }
        try {
            Configuration fc = ConfigurationProvider.getProvider(YamlConfiguration.class).load(filterFile);
            java.util.List<?> words = fc.getList("words");
            if (words != null) {
                for (Object o : words) {
                    if (o != null && !o.toString().trim().isEmpty()) target.add(o.toString().trim().toLowerCase());
                }
            }
        } catch (Exception e) { plugin.getLogger().warning("[ChatModule] Fehler beim Laden der filter.yml: " + e.getMessage()); }
    }

    // ===== Getter =====

    public Map<String, ChatChannel> getChannels()        { return Collections.unmodifiableMap(channels); }
    public ChatChannel getChannel(String id)             { return channels.get(id == null ? defaultChannel : id.toLowerCase()); }
    public ChatChannel getDefaultChannel()               { return channels.getOrDefault(defaultChannel, channels.values().iterator().next()); }
    public String getDefaultChannelId()                  { return defaultChannel; }
    public String getHelpopFormat()                      { return helpopFormat; }
    public String getHelpopPermission()                  { return helpopPermission; }
    public int getHelpopCooldown()                       { return helpopCooldown; }
    public String getHelpopConfirm()                     { return helpopConfirm; }
    public String getHelpopDiscordWebhook()              { return helpopDiscordWebhook; }
    public String getHelpopTelegramChatId()              { return helpopTelegramChatId; }
    public String getBroadcastFormat()                   { return broadcastFormat; }
    public String getBroadcastPermission()               { return broadcastPermission; }
    public boolean isPmEnabled()                         { return pmEnabled; }
    public String getPmFormatSender()                    { return pmFormatSender; }
    public String getPmFormatReceiver()                  { return pmFormatReceiver; }
    public String getPmFormatSpy()                       { return pmFormatSpy; }
    public String getPmSpyPermission()                   { return pmSpyPermission; }
    public boolean isPmRateLimitEnabled()                { return pmRateLimitEnabled; }
    public long getPmRateLimitWindowMs()                 { return pmRateLimitWindowMs; }
    public int getPmRateLimitMaxActions()                { return pmRateLimitMaxActions; }
    public long getPmRateLimitBlockMs()                  { return pmRateLimitBlockMs; }
    public String getPmRateLimitMessage()                { return pmRateLimitMessage; }
    public int getDefaultMuteDuration()                  { return defaultMuteDuration; }
    public String getMutedMessage()                      { return mutedMessage; }
    public boolean isEmojiEnabled()                      { return emojiEnabled; }
    public boolean isEmojiBedrockSupport()               { return emojiBedrockSupport; }
    public Map<String, String> getEmojiMappings()        { return Collections.unmodifiableMap(emojiMappings); }
    public boolean isDiscordEnabled()                    { return discordEnabled; }
    public String getDiscordBotToken()                   { return discordBotToken; }
    public String getDiscordGuildId()                    { return discordGuildId; }
    public int getDiscordPollInterval()                  { return discordPollInterval; }
    public String getDiscordFromFormat()                 { return discordFromFormat; }
    public String getDiscordAdminChannelId()             { return discordAdminChannelId; }
    public String getDiscordEmbedColor()                 { return discordEmbedColor; }
    public boolean isTelegramEnabled()                   { return telegramEnabled; }
    public String getTelegramBotToken()                  { return telegramBotToken; }
    public int getTelegramPollInterval()                 { return telegramPollInterval; }
    public String getTelegramFromFormat()                { return telegramFromFormat; }
    public String getTelegramAdminChatId()               { return telegramAdminChatId; }
    public int getTelegramChatTopicId()                  { return telegramChatTopicId; }
    public int getTelegramAdminTopicId()                 { return telegramAdminTopicId; }
    public boolean isLinkingEnabled()                    { return linkingEnabled; }
    public String getLinkDiscordMessage()                { return linkDiscordMessage; }
    public String getLinkTelegramMessage()               { return linkTelegramMessage; }
    public String getLinkSuccessDiscord()                { return linkSuccessDiscord; }
    public String getLinkSuccessTelegram()               { return linkSuccessTelegram; }
    public String getLinkBotSuccessDiscord()             { return linkBotSuccessDiscord; }
    public String getLinkBotSuccessTelegram()            { return linkBotSuccessTelegram; }
    public String getLinkedDiscordFormat()               { return linkedDiscordFormat; }
    public String getLinkedTelegramFormat()              { return linkedTelegramFormat; }
    public String getAdminBypassPermission()             { return adminBypassPermission; }
    public String getAdminNotifyPermission()             { return adminNotifyPermission; }
    public String getServerColor(String serverName)      { if (serverName == null) return serverColorDefault; String c = serverColors.get(serverName.toLowerCase()); return c != null ? c : serverColorDefault; }
    public Map<String, String> getServerColors()         { return Collections.unmodifiableMap(serverColors); }
    public String getServerColorDefault()                { return serverColorDefault; }
    public String getServerDisplay(String serverName)    { if (serverName == null) return ""; String d = serverDisplayNames.get(serverName.toLowerCase()); return d != null ? d : serverName; }
    public boolean isChatlogEnabled()                    { return chatlogEnabled; }
    public int getChatlogRetentionDays()                 { return chatlogRetentionDays; }
    public boolean isReportsEnabled()                    { return reportsEnabled; }
    public String getReportConfirm()                     { return reportConfirm; }
    public String getReportPermission()                  { return reportPermission; }
    public String getReportClosePermission()             { return reportClosePermission; }
    public String getReportViewPermission()              { return reportViewPermission; }
    public int getReportCooldown()                       { return reportCooldown; }
    public String getReportDiscordWebhook()              { return reportDiscordWebhook; }
    public String getReportTelegramChatId()              { return reportTelegramChatId; }
    public boolean isReportWebhookEnabled()              { return reportWebhookEnabled; }
    public ChatFilter.ChatFilterConfig getFilterConfig() { return filterConfig; }
    public boolean isMentionsEnabled()                   { return mentionsEnabled; }
    public String getMentionsHighlightColor()            { return mentionsHighlightColor; }
    public String getMentionsSound()                     { return mentionsSound; }
    public boolean isMentionsAllowToggle()               { return mentionsAllowToggle; }
    public String getMentionsNotifyPrefix()              { return mentionsNotifyPrefix; }
    public int getHistoryMaxLines()                      { return historyMaxLines; }
    public int getHistoryDefaultLines()                  { return historyDefaultLines; }
    public boolean isJoinLeaveEnabled()                  { return joinLeaveEnabled; }
    public String getJoinFormat()                        { return joinFormat; }
    public String getLeaveFormat()                       { return leaveFormat; }
    public boolean isVanishShowToAdmins()                { return vanishShowToAdmins; }
    public String getVanishJoinFormat()                  { return vanishJoinFormat; }
    public String getVanishLeaveFormat()                 { return vanishLeaveFormat; }
    public String getJoinLeaveDiscordWebhook()           { return joinLeaveDiscordWebhook; }
    public String getJoinLeaveTelegramChatId()           { return joinLeaveTelegramChatId; }
    public int getJoinLeaveTelegramThreadId()            { return joinLeaveTelegramThreadId; }
}
