package de.simolzimol.mclogger.paper.listeners;

import de.simolzimol.mclogger.paper.PaperLoggerPlugin;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import org.bukkit.EntityEffect;
import org.bukkit.entity.*;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.inventory.ItemStack;

import java.util.*;

/**
 * Logs player deaths with full context:
 *  - cause of death, killer, lost items, XP level
 *
 * @author SimolZimol
 */
public class PlayerDeathListener implements Listener {

    private final PaperLoggerPlugin plugin;

    public PlayerDeathListener(PaperLoggerPlugin plugin) {
        this.plugin = plugin;
    }

    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onDeath(PlayerDeathEvent event) {
        Player p = event.getPlayer();

        String deathMsg = event.deathMessage() != null
                ? PlainTextComponentSerializer.plainText().serialize(event.deathMessage())
                : "No death message";

        // Cause of death
        String cause = "UNKNOWN";
        if (p.getLastDamageCause() != null) {
            cause = p.getLastDamageCause().getCause().name();
        }

        // Determine killer
        String killerUuid = null, killerName = null, killerType = null;
        Entity killer = p.getKiller();
        if (killer != null) {
            killerType = killer.getType().name();
            killerName = killer instanceof Player
                    ? ((Player) killer).getName()
                    : (killer.customName() != null
                        ? PlainTextComponentSerializer.plainText().serialize(killer.customName())
                        : killer.getType().name());
            killerUuid = killer.getUniqueId().toString();
        } else if (p.getLastDamageCause() != null) {
            killerType = p.getLastDamageCause().getCause().name();
        }

        // Serialize lost items
        Map<String, Object> itemsLost = new LinkedHashMap<>();
        List<Map<String, Object>> items = new ArrayList<>();
        for (ItemStack item : event.getDrops()) {
            if (item == null) continue;
            Map<String, Object> itemMap = new HashMap<>();
            itemMap.put("type", item.getType().name());
            itemMap.put("amount", item.getAmount());
            if (item.hasItemMeta() && item.getItemMeta().hasDisplayName()) {
                itemMap.put("name", PlainTextComponentSerializer.plainText()
                        .serialize(item.getItemMeta().displayName()));
            }
            items.add(itemMap);
        }
        itemsLost.put("items", items);

        plugin.getDb().insertDeath(
                p.getUniqueId().toString(),
                p.getName(),
                p.getWorld().getName(),
                p.getLocation().getX(),
                p.getLocation().getY(),
                p.getLocation().getZ(),
                deathMsg,
                cause,
                killerUuid,
                killerName,
                killerType,
                p.getLevel(),
                itemsLost
        );
    }

    @EventHandler(priority = EventPriority.MONITOR)
    public void onRespawn(PlayerRespawnEvent event) {
        Player p = event.getPlayer();
        Map<String, Object> details = new HashMap<>();
        details.put("is_anchor_spawn", event.isAnchorSpawn());
        details.put("is_bed_spawn", event.isBedSpawn());
        details.put("world", event.getRespawnLocation().getWorld().getName());
        plugin.getDb().insertPlayerStat(
                "respawn",
                p.getUniqueId().toString(),
                p.getName(),
                null, null, details
        );
    }
}
