package com.bitnix.dirtguilds.listener;

import com.bitnix.dirtguilds.DirtGuildsPlugin;
import com.bitnix.dirtguilds.gui.GuildBankMenu;
import com.bitnix.dirtguilds.gui.GuildLevelsMenu;
import com.bitnix.dirtguilds.gui.GuildMainMenu;
import com.bitnix.dirtguilds.gui.GuildMemberManageMenu;
import com.bitnix.dirtguilds.gui.GuildMembersMenu;
import com.bitnix.dirtguilds.gui.GuildVaultMenu;
import com.bitnix.dirtguilds.guild.Guild;
import com.bitnix.dirtguilds.util.MessageUtil;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

public class GuiListener implements Listener {

    private final DirtGuildsPlugin plugin;
    private final PlainTextComponentSerializer plainText;
    private final Map<UUID, UUID> selectedMemberTargets;

    public GuiListener(DirtGuildsPlugin plugin) {
        this.plugin = plugin;
        this.plainText = PlainTextComponentSerializer.plainText();
        this.selectedMemberTargets = new HashMap<>();
    }

    @EventHandler
    public void onInventoryClick(InventoryClickEvent event) {
        if (!(event.getWhoClicked() instanceof Player player)) {
            return;
        }

        String openedTitle = plainText.serialize(event.getView().title());
        String mainTitle = title("gui.main.title", "<gold>DirtGuilds</gold>");
        String membersTitle = title("gui.members.title", "<gold>Guild Members</gold>");
        String memberManageTitle = title("gui.member-manage.title", "<gold>Manage Member</gold>");
        String bankTitle = title("gui.bank.title", "<gold>Guild Bank</gold>");
        String vaultTitle = title("gui.vault.title", "<gold>Guild Vault</gold>");
        String levelsTitle = title("gui.levels.title", "<gold>Guild Levels</gold>");

        if (openedTitle.equals(mainTitle)) {
            handleMainMenuClick(event, player);
            return;
        }

        if (openedTitle.equals(membersTitle)) {
            handleMembersMenuClick(event, player);
            return;
        }

        if (openedTitle.equals(memberManageTitle)) {
            handleMemberManageMenuClick(event, player);
            return;
        }

        if (openedTitle.equals(bankTitle)) {
            handleBankMenuClick(event, player);
            return;
        }

        if (openedTitle.equals(vaultTitle)) {
            handleVaultMenuClick(event);
            return;
        }

        if (openedTitle.equals(levelsTitle)) {
            handleLevelsMenuClick(event, player);
        }
    }

    @EventHandler
    public void onInventoryClose(InventoryCloseEvent event) {
        HumanEntity human = event.getPlayer();
        if (!(human instanceof Player player)) {
            return;
        }

        String openedTitle = plainText.serialize(event.getView().title());
        String vaultTitle = title("gui.vault.title", "<gold>Guild Vault</gold>");

        if (!openedTitle.equals(vaultTitle)) {
            return;
        }

        Guild guild = plugin.getGuildManager().getGuildByPlayer(player.getUniqueId());
        if (guild == null) {
            return;
        }

        plugin.getGuildManager().saveVaultFromInventory(guild, event.getInventory());
    }

    private void handleMainMenuClick(InventoryClickEvent event, Player player) {
        event.setCancelled(true);

        if (event.getCurrentItem() == null || event.getCurrentItem().getType().isAir()) {
            return;
        }

        Guild guild = plugin.getGuildManager().getGuildByPlayer(player.getUniqueId());

        switch (event.getCurrentItem().getType()) {
            case EMERALD -> plugin.getMessageUtil().sendRaw(player, "<yellow>Use /guild create <name></yellow>");
            case WRITABLE_BOOK -> plugin.getMessageUtil().sendRaw(player, "<yellow>Use /guild accept <guild></yellow>");
            case CHEST -> {
                if (guild != null) {
                    new GuildBankMenu(plugin).open(player, guild);
                }
            }
            case BARREL -> {
                if (guild != null) {
                    new GuildVaultMenu(plugin).open(player, guild);
                }
            }
            case EXPERIENCE_BOTTLE -> {
                if (guild != null) {
                    new GuildLevelsMenu(plugin).open(player, guild);
                }
            }
            case IRON_SWORD -> {
                if (guild != null) {
                    player.closeInventory();
                    player.performCommand("guild pvp");
                }
            }
            case PLAYER_HEAD -> {
                if (guild != null) {
                    new GuildMembersMenu(plugin).open(player, guild);
                }
            }
            case PAPER -> {
                if (guild != null) {
                    player.closeInventory();
                    player.performCommand("guild chat");
                }
            }
            default -> {
            }
        }
    }

    private void handleMembersMenuClick(InventoryClickEvent event, Player player) {
        event.setCancelled(true);

        if (event.getCurrentItem() == null || event.getCurrentItem().getType().isAir()) {
            return;
        }

        Guild guild = plugin.getGuildManager().getGuildByPlayer(player.getUniqueId());
        if (guild == null) {
            player.closeInventory();
            return;
        }

        if (event.getCurrentItem().getType() == Material.ARROW) {
            new GuildMainMenu(plugin).open(player);
            return;
        }

        if (event.getCurrentItem().getType() != Material.PLAYER_HEAD) {
            return;
        }

        UUID targetUuid = extractUuidFromItem(event.getCurrentItem().getItemMeta());
        if (targetUuid == null || !guild.isMember(targetUuid)) {
            return;
        }

        selectedMemberTargets.put(player.getUniqueId(), targetUuid);
        new GuildMemberManageMenu(plugin).open(player, guild, targetUuid);
    }

    private void handleMemberManageMenuClick(InventoryClickEvent event, Player player) {
        event.setCancelled(true);

        if (event.getCurrentItem() == null || event.getCurrentItem().getType().isAir()) {
            return;
        }

        Guild guild = plugin.getGuildManager().getGuildByPlayer(player.getUniqueId());
        if (guild == null) {
            player.closeInventory();
            return;
        }

        UUID targetUuid = selectedMemberTargets.get(player.getUniqueId());
        if (targetUuid == null || !guild.isMember(targetUuid)) {
            new GuildMembersMenu(plugin).open(player, guild);
            return;
        }

        if (!guild.canManage(player.getUniqueId()) && !guild.getOwner().equals(player.getUniqueId())) {
            plugin.getMessageUtil().send(player, "messages.no-permission");
            return;
        }

        switch (event.getCurrentItem().getType()) {
            case ENDER_PEARL -> {
                Player target = Bukkit.getPlayer(targetUuid);
                if (target == null) {
                    plugin.getMessageUtil().send(player, "messages.teleport-offline");
                    return;
                }

                player.teleport(target.getLocation());
                plugin.getMessageUtil().send(player, "messages.teleport-success", "%player%", target.getName());
            }

            case CHEST -> {
                Player target = Bukkit.getPlayer(targetUuid);
                if (target == null) {
                    plugin.getMessageUtil().send(player, "messages.teleport-offline");
                    return;
                }

                Inventory copy = Bukkit.createInventory(null, 54, MessageUtil.mm("<gold>Inventory: " + target.getName() + "</gold>"));
                copy.setContents(target.getInventory().getContents());
                player.openInventory(copy);
                plugin.getMessageUtil().send(player, "messages.inventory-opened", "%player%", target.getName());
            }

            case NAME_TAG -> {
                if (targetUuid.equals(guild.getOwner())) {
                    return;
                }

                String current = guild.getRank(targetUuid).toUpperCase();
                String next = switch (current) {
                    case "MEMBER" -> "MOD";
                    case "MOD" -> "ADMIN";
                    case "ADMIN" -> "MEMBER";
                    default -> "MEMBER";
                };

                plugin.getGuildManager().setMemberRank(guild, targetUuid, next);
                OfflinePlayer target = Bukkit.getOfflinePlayer(targetUuid);
                String name = target.getName() == null ? targetUuid.toString() : target.getName();
                plugin.getMessageUtil().send(player, "messages.rank-updated", "%player%", name, "%rank%", next);
                new GuildMemberManageMenu(plugin).open(player, guild, targetUuid);
            }

            case BARRIER -> {
                if (targetUuid.equals(guild.getOwner())) {
                    return;
                }

                plugin.getGuildManager().removeMember(guild, targetUuid);
                selectedMemberTargets.remove(player.getUniqueId());
                new GuildMembersMenu(plugin).open(player, guild);
            }

            case ARROW -> new GuildMembersMenu(plugin).open(player, guild);

            default -> {
            }
        }
    }

    private void handleBankMenuClick(InventoryClickEvent event, Player player) {
        event.setCancelled(true);

        if (event.getCurrentItem() == null || event.getCurrentItem().getType().isAir()) {
            return;
        }

        Guild guild = plugin.getGuildManager().getGuildByPlayer(player.getUniqueId());
        if (guild == null) {
            player.closeInventory();
            return;
        }

        switch (event.getCurrentItem().getType()) {
            case LIME_DYE -> {
                player.closeInventory();
                player.performCommand("guild bank deposit 100");
            }
            case RED_DYE -> {
                player.closeInventory();
                player.performCommand("guild bank withdraw 100");
            }
            case ARROW -> new GuildMainMenu(plugin).open(player);
            default -> {
            }
        }
    }

    private void handleVaultMenuClick(InventoryClickEvent event) {
        // Guild vault should be editable, so do not cancel.
    }

    private void handleLevelsMenuClick(InventoryClickEvent event, Player player) {
        event.setCancelled(true);

        if (event.getCurrentItem() == null || event.getCurrentItem().getType().isAir()) {
            return;
        }

        Guild guild = plugin.getGuildManager().getGuildByPlayer(player.getUniqueId());
        if (guild == null) {
            player.closeInventory();
            return;
        }

        switch (event.getCurrentItem().getType()) {
            case EMERALD -> {
                if (!guild.canManage(player.getUniqueId()) && !guild.getOwner().equals(player.getUniqueId())) {
                    plugin.getMessageUtil().send(player, "messages.no-permission");
                    return;
                }

                int oldLevel = guild.getLevel();
                boolean success = plugin.getGuildManager().upgradeLevel(guild);

                if (!success) {
                    if (oldLevel >= plugin.getGuildManager().getMaxConfiguredLevel()) {
                        plugin.getMessageUtil().send(player, "messages.level-maxed");
                    } else {
                        plugin.getMessageUtil().send(player, "messages.level-not-enough-money");
                    }
                    return;
                }

                plugin.getMessageUtil().send(player, "messages.level-upgraded", "%level%", String.valueOf(guild.getLevel()));
                new GuildLevelsMenu(plugin).open(player, guild);
            }
            case ARROW -> new GuildMainMenu(plugin).open(player);
            default -> {
            }
        }
    }

    private UUID extractUuidFromItem(ItemMeta meta) {
        if (meta == null || meta.lore() == null) {
            return null;
        }

        List<String> loreLines = meta.lore().stream().map(plainText::serialize).toList();
        for (String line : loreLines) {
            if (line.startsWith("UUID:")) {
                try {
                    return UUID.fromString(line.substring("UUID:".length()).trim());
                } catch (IllegalArgumentException ignored) {
                    return null;
                }
            }
        }
        return null;
    }

    private String title(String path, String fallback) {
        return plainText.serialize(MessageUtil.mm(plugin.getConfig().getString(path, fallback)));
    }
}
