package kernitus.plugin.OldCombatMechanics.utilities.reflection;

import kernitus.plugin.OldCombatMechanics.utilities.reflection.type.PacketType;
import org.bukkit.entity.Player;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.*;

/**
 * From <a href="https://www.spigotmc.org/resources/1-9-anti-collision.28770/">1.9 anti-collision plugin by Mentrixx</a>
 * Modified by kernitus to work with Rayzr's Reflector utility
 * <p>
 * I've tried to contact the author but didn't get an answer after months,
 * and as the plugin has no license decided to take some of the code
 */
public class TeamUtils {
    private static List<Player> securePlayers = new ArrayList<>();
    private static Constructor<?> packetScoreboardTeamConstructor;
    private static Field nameField;
    private static Field modeField;
    private static Field collisionRuleField;
    private static Field playersField;
    private static Map<Player, String> teamNameMap = new WeakHashMap<>();

    static {
        try {
            Class<?> packetTeamClass = Reflector.Packets.getPacket(PacketType.PlayOut, "ScoreboardTeam");
            packetScoreboardTeamConstructor = Reflector.getConstructor(packetTeamClass, 0);

            nameField = Reflector.getInaccessibleField(packetTeamClass, "a");
            modeField = Reflector.getInaccessibleField(packetTeamClass, "i");
            collisionRuleField = Reflector.getInaccessibleField(packetTeamClass, "f");
            playersField = Reflector.getInaccessibleField(packetTeamClass, "h");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public static synchronized void sendTeamPacket(Player player) {
        if (getSecurePlayers().contains(player)) {
            return;
        }

        try {
            Object packetTeamObject = packetScoreboardTeamConstructor.newInstance();

            String teamName = UUID.randomUUID().toString().substring(0, 15);
            teamNameMap.put(player, teamName);

            nameField.set(packetTeamObject, teamName);
            modeField.set(packetTeamObject, 0);
            playersField.set(packetTeamObject, Collections.singletonList(player.getName()));

            changePacketCollisionType(packetTeamObject);

            Reflector.Packets.sendPacket(player, packetTeamObject);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * Sends a packet that disbands the formerly formed team to re-enable collision.
     * <p>
     * If the player hasn't gotten a {@link #sendTeamPacket(Player)} yet, this method does nothing.
     *
     * @param player the player to send it to
     */
    public static synchronized void sendTeamRemovePacket(Player player) {
        if (!teamNameMap.containsKey(player)) {
            return;
        }
        String teamName = teamNameMap.get(player);

        try {
            Object packetTeamObject = packetScoreboardTeamConstructor.newInstance();

            nameField.set(packetTeamObject, teamName);
            modeField.set(packetTeamObject, 1);

            Reflector.Packets.sendPacket(player, packetTeamObject);

            teamNameMap.remove(player);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * Sets the collision rule to never.
     *
     * @param packetTeamObject the packet to set it on
     * @throws ReflectiveOperationException if an error occurs
     */
    public static void changePacketCollisionType(Object packetTeamObject) throws ReflectiveOperationException {
        collisionRuleField.set(packetTeamObject, "never");
    }

    public static List<Player> getSecurePlayers() {
        return securePlayers;
    }
}
@@ -260,17 +260,153 @@
 va.util.
-*
+ArrayList;%0Aimport java.util.Collections;%0Aimport java.util.List;%0Aimport java.util.Map;%0Aimport java.util.UUID;%0Aimport java.util.WeakHashMap
 ;%0A%0A/**%0A 
@@ -2241,17 +2241,50 @@
 Object, 
-0
+TeamAction.CREATE.getMinecraftId()
 );%0A     
@@ -3250,17 +3250,51 @@
 Object, 
-1
+TeamAction.DISBAND.getMinecraftId()
 );%0A%0A    
@@ -3890,24 +3890,24 @@
 Players() %7B%0A
-
         retu
@@ -3929,10 +3929,399 @@
 s;%0A    %7D
+%0A%0A    /**%0A     * The different actions a %7B@code PacketPlayOutScoreboardTeam%7D packet can represent.%0A     */%0A    private enum TeamAction %7B%0A        CREATE(0),%0A        DISBAND(1);%0A%0A        private int minecraftId;%0A%0A        TeamAction(int minecraftId) %7B%0A            this.minecraftId = minecraftId;%0A        %7D%0A%0A        public int getMinecraftId() %7B%0A            return minecraftId;%0A        %7D%0A    %7D
 %0A%7D

Remove some magic numbers in favour of an enum