package de.viper.survivalplus.listeners;

import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Sound;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.PrepareItemCraftEvent;
import org.bukkit.inventory.CraftingInventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataType;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.scheduler.BukkitRunnable;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class ToolUpgradeListener implements Listener {

    private final JavaPlugin plugin;
    private final NamespacedKey levelKey;
    private final int maxLevel;
    private final Map<Integer, Material> levelMaterials = new HashMap<>();
    private static final int REQUIRED_AMOUNT = 2; // immer 2 pro Slot

    public ToolUpgradeListener(JavaPlugin plugin) {
        this.plugin = plugin;
        this.levelKey = new NamespacedKey(plugin, "tool_level");
        this.maxLevel = plugin.getConfig().getInt("tool-upgrades.max-level", 5);

        // Material aus Config laden
        for (int i = 1; i <= maxLevel; i++) {
            String matName = plugin.getConfig().getString("tool-upgrades.levels." + i + ".material");
            if (matName != null) {
                try {
                    levelMaterials.put(i, Material.valueOf(matName.toUpperCase()));
                } catch (IllegalArgumentException e) {
                    plugin.getLogger().warning("Ungültiges Material für Level " + i + ": " + matName);
                }
            }
        }
    }

    /** Vorschau-Ergebnis setzen */
    @EventHandler
    public void onPrepareCraft(PrepareItemCraftEvent event) {
        if (!(event.getInventory() instanceof CraftingInventory)) return;
        CraftingInventory inv = (CraftingInventory) event.getInventory();
        ItemStack[] matrix = inv.getMatrix();
        if (matrix.length < 9) return; // Kein 3x3-Crafting-Tisch

        ItemStack center = matrix[4];
        // Nur eingreifen, wenn ein Werkzeug in der Mitte liegt
        if (center == null || center.getType() == Material.AIR || !isUpgradeableTool(center.getType()) || isWoodTool(center.getType())) {
            return; // Standard-Rezepte nicht beeinflussen
        }

        int currentLevel = getToolLevel(center);
        if (currentLevel >= maxLevel || currentLevel >= getMaxAllowedLevel(center.getType())) {
            inv.setResult(null);
            return;
        }

        Material requiredMat = levelMaterials.get(currentLevel + 1);
        if (requiredMat == null) {
            inv.setResult(null);
            return;
        }

        // Prüfen, ob alle Slots (außer Mitte) mind. 2 Stück vom richtigen Material haben
        for (int i = 0; i < matrix.length; i++) {
            if (i == 4) continue;
            if (matrix[i] == null || matrix[i].getType() != requiredMat || matrix[i].getAmount() < REQUIRED_AMOUNT) {
                inv.setResult(null);
                return;
            }
        }
        inv.setResult(createUpgradedTool(center, currentLevel + 1));
    }

    /** Klick auf Ergebnis-Slot handhaben + Items verbrauchen */
    @EventHandler
    public void onInventoryClick(InventoryClickEvent event) {
        if (!(event.getWhoClicked() instanceof Player)) return;
        Player player = (Player) event.getWhoClicked();
        if (!(event.getView().getTopInventory() instanceof CraftingInventory)) return;
        CraftingInventory inv = (CraftingInventory) event.getView().getTopInventory();
        if (event.getRawSlot() != 0) return; // Nur Ergebnis-Slot (Slot 0 in Werkbank)
        if (event.getCurrentItem() == null || event.getCurrentItem().getType() == Material.AIR) return;

        ItemStack[] matrix = inv.getMatrix();
        ItemStack center = matrix[4];
        if (center == null || !isUpgradeableTool(center.getType()) || isWoodTool(center.getType())) {
            plugin.getLogger().fine("Kein Upgrade-Werkzeug in der Mitte: " + (center != null ? center.getType() : "null"));
            return;
        }

        int currentLevel = getToolLevel(center);
        if (currentLevel >= maxLevel || currentLevel >= getMaxAllowedLevel(center.getType())) {
            plugin.getLogger().fine("Maximales Level erreicht für Werkzeug: " + center.getType());
            return;
        }

        Material requiredMat = levelMaterials.get(currentLevel + 1);
        if (requiredMat == null) {
            plugin.getLogger().fine("Kein Material für Level " + (currentLevel + 1));
            return;
        }

        for (int i = 0; i < matrix.length; i++) {
            if (i == 4) continue;
            if (matrix[i] == null || matrix[i].getType() != requiredMat || matrix[i].getAmount() < REQUIRED_AMOUNT) {
                plugin.getLogger().fine("Ungültiges Material in Slot " + i + ": " + (matrix[i] != null ? matrix[i].getType() : "null"));
                return;
            }
        }

        // Gültig: Event abbrechen, Upgrade geben, Items verbrauchen
        plugin.getLogger().info("Werkzeug-Upgrade für " + player.getName() + ": " + center.getType() + " auf Level " + (currentLevel + 1));
        event.setCancelled(true);
        ItemStack result = createUpgradedTool(center, currentLevel + 1);

        // Upgrade dem Spieler geben (Einzel- oder Shift-Klick)
        if (event.isShiftClick()) {
            player.getInventory().addItem(result);
        } else {
            if (event.getCursor() == null || event.getCursor().getType() == Material.AIR) {
                event.setCursor(result);
            } else {
                player.getInventory().addItem(result);
            }
        }

        // Items verbrauchen: 2 pro Slot (außer Mitte), Mitte leeren
        for (int i = 0; i < matrix.length; i++) {
            if (i == 4) {
                matrix[i] = null; // Mitte leeren
            } else if (matrix[i] != null) {
                int newAmount = matrix[i].getAmount() - REQUIRED_AMOUNT;
                if (newAmount <= 0) {
                    matrix[i] = null;
                } else {
                    matrix[i].setAmount(newAmount);
                }
            }
        }
        inv.setMatrix(matrix);
        inv.setResult(null); // Ergebnis-Slot leeren

        // Inventar-Update verzögert senden
        new BukkitRunnable() {
            @Override
            public void run() {
                player.updateInventory();
            }
        }.runTaskLater(plugin, 2L); // 2 Ticks Verzögerung
    }

    /** Effekte beim Benutzen */
    @EventHandler
    public void onBlockBreak(BlockBreakEvent event) {
        Player player = event.getPlayer();
        if (player.getGameMode() == GameMode.CREATIVE) return;

        ItemStack tool = player.getInventory().getItemInMainHand();
        if (tool == null || !isUpgradeableTool(tool.getType()) || isWoodTool(tool.getType())) return;

        int level = getToolLevel(tool);
        if (level <= 0) return;

        // Drop-Multiplikator
        int multiplier = getDropMultiplier(tool.getType());
        if (multiplier > 1) {
            event.setDropItems(false);
            for (ItemStack drop : event.getBlock().getDrops(tool, player)) {
                for (int i = 0; i < multiplier; i++) {
                    event.getBlock().getWorld().dropItemNaturally(event.getBlock().getLocation(), drop.clone());
                }
            }
        }

        // Haste-Effekt
        int hasteLevel = Math.min(5, level);
        player.addPotionEffect(new PotionEffect(PotionEffectType.HASTE, 40, hasteLevel - 1, true, false));

        // Sound
        player.playSound(player.getLocation(), Sound.BLOCK_ANVIL_USE, 0.4f, 1.6f);
    }

    /** Upgrade-Item erstellen */
    private ItemStack createUpgradedTool(ItemStack baseTool, int newLevel) {
        ItemStack upgraded = baseTool.clone();
        ItemMeta meta = upgraded.getItemMeta();
        if (meta != null) {
            meta.getPersistentDataContainer().set(levelKey, PersistentDataType.INTEGER, newLevel);
            Enchantment eff = Enchantment.getByKey(NamespacedKey.minecraft("efficiency"));
            Enchantment fortune = Enchantment.getByKey(NamespacedKey.minecraft("fortune"));
            if (eff != null) meta.addEnchant(eff, Math.min(5, newLevel), true);
            int fLevel = getFortuneForMaterial(baseTool.getType());
            if (fLevel > 0 && fortune != null) meta.addEnchant(fortune, fLevel, true);
            meta.setLore(Collections.singletonList("§7Upgrade-Level: §e" + newLevel));
            upgraded.setItemMeta(meta);
        }
        return upgraded;
    }

    /** Hilfsmethoden */
    private boolean isUpgradeableTool(Material mat) {
        String n = mat.name();
        return n.endsWith("_AXE") || n.endsWith("_PICKAXE") ||
               n.endsWith("_SHOVEL") || n.endsWith("_HOE") ||
               n.endsWith("_SWORD");
    }

    private boolean isWoodTool(Material mat) {
        return mat.name().startsWith("WOODEN");
    }

    private int getMaxAllowedLevel(Material mat) {
        String s = mat.name();
        if (s.startsWith("IRON")) return 3;
        if (s.startsWith("GOLDEN")) return 3;
        if (s.startsWith("DIAMOND")) return maxLevel;
        if (s.startsWith("NETHERITE")) return maxLevel;
        return 0;
    }

    private int getFortuneForMaterial(Material mat) {
        String s = mat.name();
        if (s.startsWith("GOLDEN")) return 1;
        if (s.startsWith("DIAMOND")) return 2;
        if (s.startsWith("NETHERITE")) return 3;
        return 0;
    }

    private int getDropMultiplier(Material mat) {
        String s = mat.name();
        if (s.startsWith("GOLDEN")) return 2;
        if (s.startsWith("DIAMOND")) return 3;
        if (s.startsWith("NETHERITE")) return 6;
        return 1;
    }

    private int getToolLevel(ItemStack item) {
        if (item == null || !item.hasItemMeta()) return 0;
        Integer lvl = item.getItemMeta().getPersistentDataContainer().get(levelKey, PersistentDataType.INTEGER);
        return lvl != null ? lvl : 0;
    }
}