package de.simolzimol.mclogger.paper.listeners;

import de.simolzimol.mclogger.paper.PaperLoggerPlugin;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.*;
import org.bukkit.event.player.PlayerBedEnterEvent;

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

/**
 * Miscellaneous player events: teleport, gamemode, bed, level,
 * arrow-shooting (as projectile), hand-swap, sleeping, etc.
 *
 * @author SimolZimol
 */
public class PlayerMiscListener implements Listener {

    private final PaperLoggerPlugin plugin;

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

    /** Teleport (all causes) */
    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onTeleport(PlayerTeleportEvent event) {
        Player p = event.getPlayer();
        if (event.getFrom().equals(event.getTo())) return; // no movement

        String cause = event.getCause().name();
        // Only log relevant causes (COMMAND, PLUGIN, NETHER_PORTAL, etc.)
        plugin.getDb().insertTeleport(
                p.getUniqueId().toString(),
                p.getName(),
                event.getFrom().getWorld().getName(),
                event.getFrom().getX(), event.getFrom().getY(), event.getFrom().getZ(),
                event.getTo().getWorld().getName(),
                event.getTo().getX(), event.getTo().getY(), event.getTo().getZ(),
                cause
        );
    }

    /** Gamemode change */
    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onGameMode(PlayerGameModeChangeEvent event) {
        Player p = event.getPlayer();
        Map<String, Object> details = new HashMap<>();
        details.put("cause", event.getCause().name());
        plugin.getDb().insertPlayerStat(
                "gamemode_change",
                p.getUniqueId().toString(),
                p.getName(),
                p.getGameMode().name(),
                event.getNewGameMode().name(),
                details
        );
    }

    /** Level change (XP) */
    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onLevelChange(PlayerLevelChangeEvent event) {
        if (Math.abs(event.getNewLevel() - event.getOldLevel()) == 0) return;
        Player p = event.getPlayer();
        plugin.getDb().insertPlayerStat(
                "level_change",
                p.getUniqueId().toString(),
                p.getName(),
                String.valueOf(event.getOldLevel()),
                String.valueOf(event.getNewLevel()),
                null
        );
    }

    /** Enter bed */
    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onBedEnter(PlayerBedEnterEvent event) {
        Player p = event.getPlayer();
        Map<String, Object> details = new HashMap<>();
        details.put("result", event.getBedEnterResult().name());
        details.put("world", event.getBed().getWorld().getName());
        details.put("x", event.getBed().getX());
        details.put("y", event.getBed().getY());
        details.put("z", event.getBed().getZ());
        plugin.getDb().insertPlayerStat("bed_enter", p.getUniqueId().toString(), p.getName(), null, null, details);
    }

    /** Leave bed */
    @EventHandler(priority = EventPriority.MONITOR)
    public void onBedLeave(PlayerBedLeaveEvent event) {
        Player p = event.getPlayer();
        Map<String, Object> details = new HashMap<>();
        details.put("world", event.getBed().getWorld().getName());
        plugin.getDb().insertPlayerStat("bed_leave", p.getUniqueId().toString(), p.getName(), null, null, details);
    }

    /** Item held change (hand slot) */
    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onItemHeld(PlayerItemHeldEvent event) {
        Player p = event.getPlayer();
        Map<String, Object> details = new HashMap<>();
        details.put("from_slot", event.getPreviousSlot());
        details.put("to_slot", event.getNewSlot());
        String newItem = p.getInventory().getItem(event.getNewSlot()) != null
                ? p.getInventory().getItem(event.getNewSlot()).getType().name() : "EMPTY";
        details.put("new_item", newItem);
        plugin.getDb().insertPlayerStat("item_held_change", p.getUniqueId().toString(), p.getName(),
                String.valueOf(event.getPreviousSlot()), String.valueOf(event.getNewSlot()), details);
    }

    /** Swap hands (F key) */
    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onSwapHands(PlayerSwapHandItemsEvent event) {
        Player p = event.getPlayer();
        Map<String, Object> details = new HashMap<>();
        if (event.getMainHandItem() != null)  details.put("main_hand", event.getMainHandItem().getType().name());
        if (event.getOffHandItem() != null)   details.put("off_hand", event.getOffHandItem().getType().name());
        plugin.getDb().insertPlayerStat("swap_hands", p.getUniqueId().toString(), p.getName(), null, null, details);
    }

    /** Fishing activity */
    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onFish(PlayerFishEvent event) {
        Player p = event.getPlayer();
        Map<String, Object> details = new HashMap<>();
        details.put("state", event.getState().name());
        if (event.getCaught() != null) details.put("caught", event.getCaught().getType().name());
        details.put("exp", event.getExpToDrop());
        plugin.getDb().insertPlayerStat("fish", p.getUniqueId().toString(), p.getName(), null, null, details);
    }

    /** Player interaction with entity */
    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onInteractEntity(PlayerInteractEntityEvent event) {
        Player p = event.getPlayer();
        Map<String, Object> details = new HashMap<>();
        details.put("entity_type", event.getRightClicked().getType().name());
        details.put("entity_uuid", event.getRightClicked().getUniqueId().toString());
        details.put("hand", event.getHand().name());
        plugin.getDb().insertPlayerStat("interact_entity", p.getUniqueId().toString(), p.getName(), null, null, details);
    }

    /** OP status changed */
    @EventHandler(priority = EventPriority.MONITOR)
    public void onOp(PlayerToggleSneakEvent event) {
        // used for OP-change – updated via upsertPlayer on the next join
    }
}
