package de.simolzimol.mclogger.paper.listeners;

import de.simolzimol.mclogger.paper.PaperLoggerPlugin;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import org.bukkit.entity.*;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.*;

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

/**
 * Logs entity events: spawns, deaths, damage, taming, breeding, explosions.
 *
 * @author SimolZimol
 */
public class EntityListener implements Listener {

    private final PaperLoggerPlugin plugin;

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

    // -------------------------------------------------------
    // Entity Spawn
    // -------------------------------------------------------
    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onSpawn(EntitySpawnEvent event) {
        Entity e = event.getEntity();
        // Skip redundant entities (projectiles etc.) to reduce DB load
        if (e instanceof Item || e instanceof ExperienceOrb || e instanceof Arrow) return;

        String playerUuid = null, playerName = null;
        if (e instanceof Player p) {
            playerUuid = p.getUniqueId().toString();
            playerName  = p.getName();
        }

        Map<String, Object> details = new HashMap<>();
        details.put("spawn_reason", e instanceof LivingEntity le ? "natural" : "other");
        details.put("has_ai", e instanceof Mob mob && mob.hasAI());

        plugin.getDb().insertEntityEvent(
                "spawn",
                e.getWorld().getName(),
                e.getLocation().getX(), e.getLocation().getY(), e.getLocation().getZ(),
                e.getType().name(),
                e.getUniqueId().toString(),
                e.customName() != null ? PlainTextComponentSerializer.plainText().serialize(e.customName()) : null,
                playerUuid, playerName,
                null, 0, details
        );
    }

    // -------------------------------------------------------
    // Entity Death
    // -------------------------------------------------------
    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onDeath(EntityDeathEvent event) {
        LivingEntity e = event.getEntity();
        if (e instanceof Player) return; // Player deaths are handled by PlayerDeathListener

        Player killer = e.getKiller();
        String killerUuid = killer != null ? killer.getUniqueId().toString() : null;
        String killerName = killer != null ? killer.getName() : null;

        String cause = e.getLastDamageCause() != null
                ? e.getLastDamageCause().getCause().name() : "UNKNOWN";

        Map<String, Object> details = new HashMap<>();
        details.put("drops", event.getDrops().size());
        details.put("exp", event.getDroppedExp());

        plugin.getDb().insertEntityEvent(
                "death",
                e.getWorld().getName(),
                e.getLocation().getX(), e.getLocation().getY(), e.getLocation().getZ(),
                e.getType().name(),
                e.getUniqueId().toString(),
                e.customName() != null ? PlainTextComponentSerializer.plainText().serialize(e.customName()) : null,
                killerUuid, killerName,
                cause, 0, details
        );
    }

    // -------------------------------------------------------
    // Entity Damage (player-inflicted only)
    // -------------------------------------------------------
    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onDamage(EntityDamageByEntityEvent event) {
        if (!(event.getDamager() instanceof Player p)) return;
        if (event.getEntity() instanceof Player) return; // PvP separat nicht nötig
        Entity target = event.getEntity();

        plugin.getDb().insertEntityEvent(
                "damage",
                target.getWorld().getName(),
                target.getLocation().getX(), target.getLocation().getY(), target.getLocation().getZ(),
                target.getType().name(),
                target.getUniqueId().toString(),
                target.customName() != null ? PlainTextComponentSerializer.plainText().serialize(target.customName()) : null,
                p.getUniqueId().toString(),
                p.getName(),
                event.getCause().name(),
                event.getFinalDamage(),
                null
        );
    }

    // -------------------------------------------------------
    // Entity Tame
    // -------------------------------------------------------
    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onTame(EntityTameEvent event) {
        if (!(event.getOwner() instanceof Player p)) return;
        Entity e = event.getEntity();

        plugin.getDb().insertEntityEvent(
                "tame",
                e.getWorld().getName(),
                e.getLocation().getX(), e.getLocation().getY(), e.getLocation().getZ(),
                e.getType().name(),
                e.getUniqueId().toString(),
                null,
                p.getUniqueId().toString(),
                p.getName(),
                null, 0, null
        );
    }

    // -------------------------------------------------------
    // Entity Breed
    // -------------------------------------------------------
    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onBreed(EntityBreedEvent event) {
        Entity e = event.getEntity();
        Player breeder = event.getBreeder() instanceof Player pl ? pl : null;

        Map<String, Object> details = new HashMap<>();
        details.put("mother", event.getMother().getType().name());
        details.put("father", event.getFather().getType().name());
        if (event.getBredWith() != null) details.put("bred_with", event.getBredWith().getType().name());

        plugin.getDb().insertEntityEvent(
                "breed",
                e.getWorld().getName(),
                e.getLocation().getX(), e.getLocation().getY(), e.getLocation().getZ(),
                e.getType().name(),
                e.getUniqueId().toString(),
                null,
                breeder != null ? breeder.getUniqueId().toString() : null,
                breeder != null ? breeder.getName() : null,
                null, 0, details
        );
    }

    // -------------------------------------------------------
    // Explosion (Creeper, TNT, etc.)
    // -------------------------------------------------------
    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onExplode(EntityExplodeEvent event) {
        Entity e = event.getEntity();

        Map<String, Object> details = new HashMap<>();
        details.put("blocks_destroyed", event.blockList().size());
        details.put("yield", event.getYield());

        plugin.getDb().insertEntityEvent(
                "explode",
                e.getWorld().getName(),
                e.getLocation().getX(), e.getLocation().getY(), e.getLocation().getZ(),
                e.getType().name(),
                e.getUniqueId().toString(),
                null,
                null, null,
                null, 0, details
        );
    }

    // -------------------------------------------------------
    // PvP – Damage between players
    // -------------------------------------------------------
    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onPvP(EntityDamageByEntityEvent event) {
        if (!(event.getEntity() instanceof Player victim)) return;
        if (!(event.getDamager() instanceof Player attacker)) return;

        Map<String, Object> details = new HashMap<>();
        details.put("cause", event.getCause().name());
        details.put("damage", event.getFinalDamage());
        details.put("victim_health_after",
                Math.max(0, victim.getHealth() - event.getFinalDamage()));

        plugin.getDb().insertPlayerStat(
                "pvp_hit",
                attacker.getUniqueId().toString(),
                attacker.getName(),
                attacker.getName(),
                victim.getName(),
                details
        );
    }
}
