package eu.mrneznamy.mrultimatelibrary.config;

import eu.mrneznamy.mrultimatelibrary.utils.MrLibConsoleSayer;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.java.JavaPlugin;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.*;

/**
 * Converts old configuration files to new format with comments
 * Handles migration of existing user configs to centralized system
 */
public class MrLibConfigConverter {
    
    private final JavaPlugin plugin;
    private final Map<String, List<ConversionRule>> conversionRules = new HashMap<>();
    private final Map<String, List<String>> fileComments = new HashMap<>();
    
    public MrLibConfigConverter(JavaPlugin plugin) {
        this.plugin = plugin;
        setupConversionRules();
        setupComments();
    }
    
    /**
     * Check if config should be skipped from conversion
     * @param configName Name of config file
     * @return true if should skip conversion
     */
    private boolean shouldSkipConversion(String configName) {
        String pluginName = plugin.getName();
        
        
        if (pluginName.equals("MrUltimateShop")) {
            if (configName.equals("menu.yml") ||
                configName.equals("tracker.yml") ||
                configName.equals("sell-gui.yml") ||
                configName.equals("sell-all-gui.yml") ||
                configName.equals("buy-gui.yml") ||
                configName.startsWith("Shops/")) {
                return true;
            }
        }
        
        
        
        if (pluginName.equals("MrUltimateJobs")) {
            if (configName.equals("events.yml") || 
                configName.equals("boosters.yml") ||
                configName.equals("tournaments.yml") ||
                configName.equals("data.yml") ||
                configName.startsWith("Jobs/") ||
                configName.startsWith("Menus/")) {
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * Converts old config to new format
     * @param configName Name of config file (e.g. "config.yml")
     * @return true if conversion was successful
     */
    public boolean convertConfig(String configName) {
        
        if (shouldSkipConversion(configName)) {
            return false;
        }
        
        File oldFile = new File(plugin.getDataFolder(), configName);
        
        if (!oldFile.exists()) {
            return false; 
        }
        
        try {
            
            File backupFolder = new File(plugin.getDataFolder(), "backupFiles");
            if (!backupFolder.exists()) {
                backupFolder.mkdirs();
            }
            
            
            String timestamp = new java.text.SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(new java.util.Date());
            File backupFile = new File(backupFolder, configName + ".old-backup." + timestamp);
            Files.copy(oldFile.toPath(), backupFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
            MrLibConsoleSayer.MrSay_Info("[" + plugin.getName() + "] Backed up old " + configName + " to backupFiles/" + backupFile.getName());
            
            
            YamlConfiguration oldConfig = YamlConfiguration.loadConfiguration(oldFile);
            
            
            MrLibYamlConfiguration newConfig = new MrLibYamlConfiguration();
            
            
            List<ConversionRule> rules = conversionRules.get(configName);
            if (rules != null) {
                for (ConversionRule rule : rules) {
                    rule.apply(oldConfig, newConfig);
                }
            } else {
                
                for (String key : oldConfig.getKeys(true)) {
                    if (!oldConfig.isConfigurationSection(key)) {
                        newConfig.set(key, oldConfig.get(key));
                    }
                }
            }
            
            
            List<String> comments = fileComments.get(configName);
            if (comments != null) {
                for (String comment : comments) {
                    String[] parts = comment.split("\\|", 2);
                    if (parts.length == 2) {
                        newConfig.addComment(parts[0], parts[1]);
                    }
                }
            }
            
            
            newConfig.save(oldFile);
            
            MrLibConsoleSayer.MrSay_Success("[" + plugin.getName() + "] Converted " + configName + " to new format");
            return true;
            
        } catch (Exception e) {
            MrLibConsoleSayer.MrSay_Error("[" + plugin.getName() + "] Failed to convert " + configName + ": " + e.getMessage());
            return false;
        }
    }
    
    /**
     * Checks if config needs conversion
     */
    public boolean needsConversion(String configName) {
        File configFile = new File(plugin.getDataFolder(), configName);
        if (!configFile.exists()) {
            return false;
        }
        
        
        YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
        
        
        if (config.contains("MrUltimateLibrary-Configs-Version")) {
            return false;
        }

        String versionKey = configName.replace(".yml", "") + "-version";
        return !config.contains(versionKey);
    }
    
    /**
     * Setup conversion rules for each plugin
     */
    private void setupConversionRules() {
        if (plugin.getName().equals("MrUltimateShop")) {
            setupMrUltimateShopRules();
        } else if (plugin.getName().equals("MrUltimateHoppers")) {
            setupMrUltimateHoppersRules();
        } else if (plugin.getName().equals("MrUltimateJobs")) {
            setupMrUltimateJobsRules();
        } else if (plugin.getName().equals("MrVoteTrain")) {
            setupMrVoteTrainRules();
        } else if (plugin.getName().equals("MrSellChests")) {
            setupMrSellChestsRules();
        }
    }
    
    /**
     * Setup comments for each plugin
     */
    private void setupComments() {
        if (plugin.getName().equals("MrUltimateShop")) {
            setupMrUltimateShopComments();
        } else if (plugin.getName().equals("MrSellChests")) {
            setupMrSellChestsComments();
        }
    }
    
    
    
    
    private void setupMrUltimateShopRules() {
        List<ConversionRule> rules = new ArrayList<>();
        
        
        rules.add((oldConfig, newConfig) -> {
            newConfig.set("config-version", 1);
        });
        
        
        rules.add((oldConfig, newConfig) -> {
            for (String key : oldConfig.getKeys(true)) {
                if (!oldConfig.isConfigurationSection(key)) {
                    Object value = oldConfig.get(key);
                    
                    
                    if (key.startsWith("MrUltimateShop.")) {
                        newConfig.set(key, value);
                    }
                    
                    else if (key.startsWith("Database.") || key.startsWith("economy.") || 
                             key.startsWith("Logging.") || key.startsWith("World-Settings.") ||
                             key.startsWith("Features.") || key.startsWith("shop.") || 
                             key.startsWith("messages.") || key.startsWith("ChestShops.")) {
                        newConfig.set("MrUltimateShop." + key, value);
                    }
                    
                    else {
                        newConfig.set(key, value);
                    }
                }
            }
        });
        
        
        rules.add((oldConfig, newConfig) -> {
            if (!newConfig.contains("MrUltimateShop.Database")) {
                newConfig.set("MrUltimateShop.Database.Type", "yml");
                newConfig.set("MrUltimateShop.Database.SQLite.FileName", "ultimateshop.db");
                newConfig.set("MrUltimateShop.Database.MySQL.Host", "localhost");
                newConfig.set("MrUltimateShop.Database.MySQL.Port", 3306);
                newConfig.set("MrUltimateShop.Database.MySQL.Database", "ultimateshop");
                newConfig.set("MrUltimateShop.Database.MySQL.Username", "root");
                newConfig.set("MrUltimateShop.Database.MySQL.Password", "");
            }
        });
        
        
        rules.add((oldConfig, newConfig) -> {
            
            if (newConfig.contains("MrUltimateShop.economy.use-vault")) {
                boolean useVault = newConfig.getBoolean("MrUltimateShop.economy.use-vault", true);
                String symbol = newConfig.getString("MrUltimateShop.economy.currency-symbol", "$");
                String format = newConfig.getString("MrUltimateShop.economy.number-format", "#,##0.00");
                
                
                newConfig.set("MrUltimateShop.economy.use-vault", null);
                newConfig.set("MrUltimateShop.economy.currency-symbol", null);
                newConfig.set("MrUltimateShop.economy.number-format", null);
                
                
                newConfig.set("MrUltimateShop.Economy.Vault.Enabled", useVault);
                newConfig.set("MrUltimateShop.Economy.Vault.Symbol", symbol);
                newConfig.set("MrUltimateShop.Economy.Vault.Number-Format", format);
                newConfig.set("MrUltimateShop.Economy.MrVoteTrain.Enabled", false);
                newConfig.set("MrUltimateShop.Economy.MrVoteTrain.Symbol", " VB");
                newConfig.set("MrUltimateShop.Economy.MrVoteTrain.Number-Format", "#,##0");
            }
        });
        
        conversionRules.put("config.yml", rules);
        
        
        List<ConversionRule> messagesRules = new ArrayList<>();
        
        messagesRules.add((oldConfig, newConfig) -> {
            newConfig.set("messages-version", 1);
        });
        
        messagesRules.add((oldConfig, newConfig) -> {
            for (String key : oldConfig.getKeys(true)) {
                if (!oldConfig.isConfigurationSection(key)) {
                    Object value = oldConfig.get(key);
                    
                    
                    if (key.startsWith("MrUltimateShop.")) {
                        newConfig.set(key, value);
                    }
                    
                    else if (key.startsWith("general.") || key.startsWith("shop.") || 
                             key.startsWith("sell.") || key.startsWith("sell-gui.") ||
                             key.startsWith("buysell.") || key.startsWith("errors.") ||
                             key.startsWith("commands.") || key.startsWith("Chest-Shop.")) {
                        
                        String messageKey = key.substring(key.indexOf(".") + 1);
                        String messageText = value.toString();
                        if (!messageText.contains("(!message!)") && !messageText.contains("(!NOPREFIX!)")) {
                            messageText = "(!message!)" + messageText;
                        }
                        newConfig.set("MrUltimateShop." + messageKey.replace(".", "-"), messageText);
                    }
                    
                    else {
                        newConfig.set(key, value);
                    }
                }
            }
        });
        
        conversionRules.put("messages.yml", messagesRules);
    }
    
    private void setupMrUltimateShopComments() {
        
    }
    
    
    
    private void setupMrUltimateHoppersRules() {
        
    }
    
    private void setupMrUltimateJobsRules() {
        
        List<ConversionRule> messageRules = new ArrayList<>();
        
        
        messageRules.add((oldConfig, newConfig) -> {
            newConfig.set("messages-version", 1);
        });
        
        
        messageRules.add((oldConfig, newConfig) -> {
            MrLibConsoleSayer.MrSay_Info("Converting messages.yml for MrUltimateJobs...");
            
            
            for (String key : oldConfig.getKeys(true)) {
                if (oldConfig.isString(key)) {
                    String messageText = oldConfig.getString(key);
                    if (messageText != null && !messageText.trim().isEmpty()) {
                        
                        messageText = messageText.replace("{prefix}", "");
                        
                        
                        boolean hasNoPrefix = messageText.contains("(!NOPREFIX!)");
                        boolean hasMessageTag = messageText.contains("(!message!)");
                        boolean hasTitleTag = messageText.contains("(!title!)");
                        boolean hasActionbarTag = messageText.contains("(!actionbar!)");
                        boolean hasSubtitleTag = messageText.contains("(!subtitle!)");
                        
                        
                        boolean isActionbarKey = key.toLowerCase().contains("actionbar");
                        boolean isGuiKey = key.toLowerCase().contains("name") || 
                                          key.toLowerCase().contains("active") || 
                                          key.toLowerCase().contains("inactive") ||
                                          key.toLowerCase().contains("display-name") ||
                                          key.toLowerCase().contains("material") ||
                                          key.toLowerCase().contains("custom-model-data") ||
                                          key.toLowerCase().contains("glowing") ||
                                          key.toLowerCase().contains("description") ||
                                          key.toLowerCase().contains("lore");
                        
                        
                        if (hasTitleTag || hasActionbarTag || hasSubtitleTag || isActionbarKey || isGuiKey) {
                            messageText = messageText.replaceAll("\\(![^!]*!\\)", "");
                        } else if (!hasMessageTag && !hasNoPrefix && !hasTitleTag && !hasActionbarTag && !hasSubtitleTag) {
                            messageText = "(!message!)" + messageText;
                        }
                        
                        newConfig.set("MrUltimateJobs." + key, messageText);
                    }
                }
            }
        });
        
        
        messageRules.add((oldConfig, newConfig) -> {
            List<String> messageComments = new ArrayList<>();
            messageComments.add("_HEADER_|# MrUltimateJobs Messages Configuration");
            messageComments.add("_HEADER_|# Use & for color codes");
            messageComments.add("_HEADER_|# Available placeholders: [PlayerName], [Level], [XP], [Money], [Job], [EventName], [TournamentName]");
            messageComments.add("_HEADER_|# ========================================");
            messageComments.add("_HEADER_|# Available tags:");
            messageComments.add("_HEADER_|#     (!message!) (!title!) (!subtitle!) (!actionbar!)");
            messageComments.add("_HEADER_|#     (!sound:SOUND!) (!close!) (!NOPREFIX!)");
            messageComments.add("_HEADER_|# ========================================");
            
            messageComments.add("messages-version|# Do not change this! Used for automatic config updates");
            
            newConfig.setComments("", messageComments);
        });
        
        
        conversionRules.put("messages.yml", messageRules);
    }
    
    private void setupMrVoteTrainRules() {
        
    }
    
    

    private void setupMrSellChestsRules() {
        List<ConversionRule> rules = new ArrayList<>();
        
        
        rules.add((oldConfig, newConfig) -> {
            newConfig.set("MrUltimateLibrary-Configs-Version", "1.0.0");
        });
        
        
        rules.add((oldConfig, newConfig) -> {
            for (String key : oldConfig.getKeys(true)) {
                if (!oldConfig.isConfigurationSection(key)) {
                    Object value = oldConfig.get(key);
                    if (key.equalsIgnoreCase("config-version")) continue;

                    if (key.startsWith("MrSellChests.")) {
                        newConfig.set(key, value);
                    } else if (key.startsWith("SellChests.")) {
                        newConfig.set("MrSellChests." + key, value);
                    } else if (key.startsWith("Database.") || key.startsWith("Holograms.") || 
                             key.startsWith("Economy.") || key.startsWith("SettingsMenu.") ||
                             key.startsWith("OfflineSell") || key.startsWith("SellPrices.") ||
                             key.startsWith("Sell-Message.")) {
                        newConfig.set("MrSellChests." + key, value);
                    } else {
                        newConfig.set(key, value);
                    }
                }
            }
        });
        
        conversionRules.put("config.yml", rules);
        
        List<ConversionRule> msgRules = new ArrayList<>();
        msgRules.add((oldConfig, newConfig) -> {
            newConfig.set("MrUltimateLibrary-Configs-Version", "1.0.0");
            for (String key : oldConfig.getKeys(true)) {
                if (!oldConfig.isConfigurationSection(key)) {
                    newConfig.set(key, oldConfig.get(key));
                }
            }
        });
        conversionRules.put("messages.yml", msgRules);
    }

    private void setupMrSellChestsComments() {
        List<String> header = new ArrayList<>();
        header.add("# ========================================");
        header.add("#     MrSellChests Configuration");
        header.add("#     ");
        header.add("#     All configuration options are described");
        header.add("#     with comments to help you understand");
        header.add("#     what each setting does.");
        header.add("# ========================================");
        
        MrLibYamlConfiguration config = new MrLibYamlConfiguration();
        config.setHeaderComments(header);
        
        
        config.addComment("MrSellChests.Database", "# Database configuration - stores sell chest data\n# Types: yml (default), sqlite, mysql");
        config.addComment("MrSellChests.Database.Type", "# Storage type\n# yml - stores data in data.yml and boosters.yml files (default, no setup required)\n# sqlite - stores data in a local database file (good for medium servers)\n# mysql - stores data in a MySQL database (best for large servers or networks)");
        config.addComment("MrSellChests.Database.SQLite", "# SQLite settings (only used if Type: sqlite)");
        config.addComment("MrSellChests.Database.SQLite.FileName", "# Database file name");
        config.addComment("MrSellChests.Database.MySQL", "# MySQL settings (only used if Type: mysql)");
        config.addComment("MrSellChests.Database.MySQL.Host", "# MySQL server host");
        config.addComment("MrSellChests.Database.MySQL.Port", "# MySQL server port (default: 3306)");
        config.addComment("MrSellChests.Database.MySQL.Database", "# MySQL database name");
        config.addComment("MrSellChests.Database.MySQL.Username", "# MySQL username");
        config.addComment("MrSellChests.Database.MySQL.Password", "# MySQL password");
        
        config.addComment("MrSellChests.OfflineSell", "# Offline selling\n# If true, sell chests continue selling while the player is offline\n# If false, sell chests only work when the player is online");
        
        config.addComment("MrSellChests.Holograms", "# Hologram settings - displays information above sell chests");
        config.addComment("MrSellChests.Holograms.Enabled", "# Enable or disable holograms");
        config.addComment("MrSellChests.Holograms.Provider", "# Hologram provider\n# MrUltimateLibrary - native holograms, no plugin required (recommended)");
        config.addComment("MrSellChests.Holograms.UpdateInterval", "# How often to update hologram text (in ticks, 20 ticks = 1 second)\n# Lower values = more frequent updates but more server resources");
        
        config.addComment("MrSellChests.SellPrices", "# Sell prices configuration");
        config.addComment("MrSellChests.SellPrices.Provider", "# Price provider\n# FILE - uses sell-prices.yml file (included with plugin)\n# SHOPGUI+ - uses prices from ShopGUIPlus plugin\n# EconomyShopGUI - uses prices from EconomyShopGUI plugin\n# MrUltimateShop - uses prices from MrUltimateShop plugin\n# ExcellentShop - uses prices from ExcellentShop plugin");
        
        config.addComment("MrSellChests.Economy", "# Economy settings");
        config.addComment("MrSellChests.Economy.Enabled", "# Enable economy integration");
        config.addComment("MrSellChests.Economy.Provider", "# Economy provider (currently only Vault is supported)");
        
        config.addComment("MrSellChests.Sell-Message", "# Sell message settings\n# Sends a message to players about their earnings");
        config.addComment("MrSellChests.Sell-Message.Enabled", "# Enable periodic sell messages");
        config.addComment("MrSellChests.Sell-Message.Interval", "# How often to send messages (in minutes)\n# Example: 1 = every 1 minute, 5 = every 5 minutes");
        config.addComment("MrSellChests.Sell-Message.Message", "# Message format (prefix is not used for this message)\n# Placeholders:\n# [MoneyEarned] - amount of money earned\n# [Interval] - time interval in minutes");
        
        config.addComment("MrSellChests.SellChests", "# Sell chest types configuration\n# You can create multiple types of sell chests with different settings\n# Players can have custom chest types here");
        
        config.addComment("MrSellChests.SettingsMenu", "# Menu title");
        config.addComment("MrSellChests.SettingsMenu.titleforsellinv", "# Sell inventory title");
        config.addComment("MrSellChests.SettingsMenu.size", "# Menu size (must be multiple of 9)");
        
        config.addComment("MrSellChests.SettingsMenu.Filters", "# Decorative items (filters)");
        config.addComment("MrSellChests.SettingsMenu.Filters.1", "# First decoration pattern");
        config.addComment("MrSellChests.SettingsMenu.Filters.1.slot", "# Slots where this item appears (comma-separated)");
        config.addComment("MrSellChests.SettingsMenu.Filters.2", "# Second decoration pattern");
        
        config.addComment("MrSellChests.SettingsMenu.items", "# Functional items in the menu");
        config.addComment("MrSellChests.SettingsMenu.items.sell_inventory", "# Sell inventory button");
        config.addComment("MrSellChests.SettingsMenu.items.statistics", "# Statistics display");
        config.addComment("MrSellChests.SettingsMenu.items.toggle_hologram", "# Toggle hologram button");
        config.addComment("MrSellChests.SettingsMenu.items.trasher", "# Item trasher mode button\n# Controls what happens to non-sellable items");
        config.addComment("MrSellChests.SettingsMenu.items.trasher.Items.REMOVE", "# Remove mode - deletes non-sellable items");
        config.addComment("MrSellChests.SettingsMenu.items.trasher.Items.KEEP", "# Keep mode - keeps non-sellable items in inventory");
        config.addComment("MrSellChests.SettingsMenu.items.trasher.Items.TRANSFER", "# Transfer mode - moves non-sellable items to linked chests");
        config.addComment("MrSellChests.SettingsMenu.items.trasher.Items.TRANSFER.Link_Item", "# Link chest button (only visible in TRANSFER mode)");
        config.addComment("MrSellChests.SettingsMenu.items.chunk_collector", "# Chunk collector toggle\n# Automatically collects items from the chunk");
        config.addComment("MrSellChests.SettingsMenu.items.invite_players", "# Invite Players button (only visible to owners)");
        config.addComment("MrSellChests.SettingsMenu.items.charge_chest", "# Charge chest button (only for CHARGING type)");
        
        
        
        for (Map.Entry<String, String> entry : config.getComments().entrySet()) {
            addFileComment("config.yml", entry.getKey() + "|" + entry.getValue());
        }
        for (String h : header) {
            addFileComment("config.yml", "_HEADER_|" + h);
        }
    }
    
    private void addFileComment(String file, String comment) {
        fileComments.computeIfAbsent(file, k -> new ArrayList<>()).add(comment);
    }

    /**
     * Conversion rule interface
     */
    @FunctionalInterface
    public interface ConversionRule {
        void apply(YamlConfiguration oldConfig, MrLibYamlConfiguration newConfig);
    }
}
