/*
 *   This file is a part of the SteamWar software.
 *
 *   Copyright (C) 2025 SteamWar.de-Serverteam
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Affero General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *   GNU Affero General Public License for more details.
 *
 *   You should have received a copy of the GNU Affero General Public License
 *   along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

package de.steamwar.bausystem.features.warp;

import de.steamwar.bausystem.region.Region;
import de.steamwar.core.Core;
import de.steamwar.entity.RArmorStand;
import de.steamwar.entity.REntityServer;
import de.steamwar.linkage.Linked;
import org.bukkit.*;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.*;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;

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

@Linked
public class WarpListener implements Listener {

    private Map<Player, REntityServer> warpEntityServer = new HashMap<>();
    private Map<Player, List<Location>> selected = new HashMap<>();

    @EventHandler
    public void onPlayerItemHeld(PlayerItemHeldEvent e) {
        ItemStack itemStack = e.getPlayer().getInventory().getItem(e.getNewSlot());
        Material material = itemStack == null ? Material.AIR : itemStack.getType();
        reshow(e.getPlayer(), material, e.getPlayer().isSneaking());
    }

    @EventHandler
    public void onPlayerMove(PlayerMoveEvent event) {
        for (Player p : Bukkit.getOnlinePlayers()) {
            reshow(p, p.getInventory().getItemInMainHand().getType(), p.isSneaking());
        }
    }

    @EventHandler
    public void onPlayerToggleSneak(PlayerToggleSneakEvent event) {
        reshow(event.getPlayer(), event.getPlayer().getInventory().getItemInMainHand().getType(), event.isSneaking());
    }

    private void reshow(Player p, Material material, boolean sneaking) {
        REntityServer entityServer = warpEntityServer.get(p);
        if (entityServer != null) {
            entityServer.close();
        }
        if (material != Material.COMPASS) {
            warpEntityServer.remove(p);
            return;
        }

        selected.remove(p);
        entityServer = new REntityServer();
        entityServer.addPlayer(p);
        warpEntityServer.put(p, entityServer);

        Vector current = p.getLocation().clone().add(p.getLocation().getDirection().multiply(5)).toVector();

        Map<String, Location> locations = new HashMap<>();
        if (sneaking) {
            Bukkit.getOnlinePlayers().forEach(player -> {
                locations.put(player.getName(), player.getLocation());
            });
        } else {
            Warp.getWarps().forEach(warp -> {
                locations.put(warp.getName(), warp.getLocation());
            });
            Region region = Region.getRegion(p.getLocation());
            if (!region.getBuildArea().isEmpty()) {
                locations.put("Copy", region.getBuildArea().getCopyPoint().toLocation(p).add(0.5, 0, 0.5));
            }
            if (!region.getTestblockArea().isEmpty()) {
                locations.put("TestBlock", region.getTestblockArea().getCopyPoint().toLocation(p).add(0.5, 0, 0.5));
            }
        }

        REntityServer finalEntityServer = entityServer;
        locations.forEach((name, location) -> {
            Vector vector = location.toVector().subtract(p.getLocation().toVector());
            if (vector.getX() * vector.getX() + vector.getZ() * vector.getZ() < 25) {
                return;
            }
            vector.setY(0);

            Vector position = p.getLocation().toVector().clone().add(vector.normalize().multiply(5));
            position.setY(p.getLocation().getY() - (Core.getVersion() >= 20 ? 0 : 1));

            if ((position.getX() - current.getX()) * (position.getX() - current.getX()) + (position.getZ() - current.getZ()) * (position.getZ() - current.getZ()) < 0.1) {
                name = "§a§l" + name;
                selected.computeIfAbsent(p, player -> new ArrayList<>()).add(location);
            }
            RArmorStand armorStand = new RArmorStand(finalEntityServer, position.toLocation(p.getWorld()), RArmorStand.Size.MARKER);
            armorStand.setDisplayName(name);
            armorStand.setNoGravity(true);
            armorStand.setInvisible(true);
        });
    }

    @EventHandler(priority = EventPriority.LOWEST)
    public void onPlayerInteract(PlayerInteractEvent event) {
        if (event.getPlayer().getInventory().getItemInMainHand().getType() != Material.COMPASS) {
            return;
        }
        if (event.getAction() != Action.RIGHT_CLICK_AIR) {
            return;
        }
        List<Location> locations = selected.getOrDefault(event.getPlayer(), new ArrayList<>());
        if (locations.size() != 1) {
            return;
        }
        Location location = locations.get(0);
        event.getPlayer().teleport(location);
        event.getPlayer().playSound(location, Sound.ENTITY_ENDERMAN_TELEPORT, SoundCategory.PLAYERS, 1, 1);
        event.setCancelled(true);
    }

    @EventHandler
    public void onPlayerQuit(PlayerQuitEvent event) {
        warpEntityServer.computeIfPresent(event.getPlayer(), (player, rEntityServer) -> {
            rEntityServer.close();
            return null;
        });
        selected.remove(event.getPlayer());
    }
}
