// • ▌ ▄ ·.  ▄▄▄·  ▄▄ • ▪   ▄▄· ▄▄▄▄·  ▄▄▄·  ▐▄▄▄  ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀  █▪▀▀▀ ▀  ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀  ▀  ▀ ▀▀  █▪ ▀▀▀
//      Magicbane Emulator Project © 2013 - 2022
//                www.magicbane.com


package engine.workthreads;
import engine.Enum;
import engine.InterestManagement.WorldGrid;
import engine.gameManager.*;
import engine.objects.*;
import engine.server.MBServerStatics;
import org.pmw.tinylog.Logger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;

    public class ZergMechanicThread implements Runnable {
        private final Mine mine;
        private final Bane bane;
        private final HashSet<PlayerCharacter> affectedPlayers = new HashSet<>();

        public ZergMechanicThread(Bane b, Mine m) {
            this.mine = m;
            this.bane = b;
        }

        @Override
        public void run() {
            if (mine != null)
                RunMineMechanic();
            if (bane != null)
                RunBaneMechanic();
        }

        private void RunMineMechanic() {
            Building tower = BuildingManager.getBuildingFromCache(mine.getBuildingID());
            float zoneBounds = Enum.CityBoundsType.GRID.extents * 0.5f;

            while (mine.isActive) {
                HashSet<AbstractWorldObject> currentPlayers = WorldGrid.getObjectsInRangePartial(tower.loc, zoneBounds, MBServerStatics.MASK_PLAYER);

                for (AbstractWorldObject playerObject : currentPlayers) {
                    PlayerCharacter player = (PlayerCharacter) playerObject;

                    affectedPlayers.add(player);

                    mine._recentMemory.remove(player.getObjectUUID());

                    mine._playerMemory.add(player.getObjectUUID());
                }

                try {
                    mine.onExit(currentPlayers);
                } catch (Exception e) {
                    Logger.error(e.getMessage());
                }

                mine.dividedPlayers = new HashMap<>();
                for (Integer playerID : mine._playerMemory) {
                    PlayerCharacter player = PlayerCharacter.getFromCache(playerID);
                    Guild nation = player.getGuild().getNation();
                    mine.dividedPlayers.computeIfAbsent(nation, k -> new ArrayList<>()).add(playerID);
                }

                for (Integer playerID : mine._playerMemory) {
                    PlayerCharacter player = PlayerCharacter.getFromCache(playerID);
                    Guild nation = player.getGuild().getNation();

                    if (mine.dividedPlayers.containsKey(nation)) {
                        int count = mine.dividedPlayers.get(nation).size();
                        player.ZergMultiplier = ZergManager.getCurrentMultiplier(count, mine.capSize);
                        player.mineAppliedID = mine.getObjectUUID();
                    } else {
                        player.ZergMultiplier = 1.0f;
                        player.mineAppliedID = 0;
                    }
                }
            }

            resetZergMultiplier();
        }

        private void RunBaneMechanic() {
            while (bane.getSiegePhase().equals(Enum.SiegePhase.WAR)) {
                HashSet<AbstractWorldObject> currentPlayers = WorldGrid.getObjectsInRangePartial(bane.getCity().loc, Enum.CityBoundsType.GRID.extents * 2.0f, MBServerStatics.MASK_PLAYER);
                Guild attacker = bane.getStone().getGuild().getNation();
                Guild defender = bane.getCity().getGuild().getNation();
                ArrayList<PlayerCharacter> attackers = new ArrayList<>();
                ArrayList<PlayerCharacter> defenders = new ArrayList<>();

                for (AbstractWorldObject awo : currentPlayers) {
                    PlayerCharacter pc = (PlayerCharacter) awo;
                    affectedPlayers.add(pc);

                    if (!pc.getGuild().getNation().equals(attacker) && !pc.getGuild().getNation().equals(defender)) {
                        pc.teleport(pc.bindLoc);
                        pc.ZergMultiplier = 1.0f;
                    }

                    if (pc.getGuild().getNation().equals(attacker))
                        attackers.add(pc);

                    if (pc.getGuild().getNation().equals(defender))
                        defenders.add(pc);
                }

                for (PlayerCharacter pc : attackers) {
                    pc.ZergMultiplier = ZergManager.getCurrentMultiplier(attackers.size(), bane.capSize);
                }

                for (PlayerCharacter pc : defenders) {
                    pc.ZergMultiplier = ZergManager.getCurrentMultiplier(defenders.size(), bane.capSize);
                }
            }

            resetZergMultiplier();
        }

        private void resetZergMultiplier() {
            for (PlayerCharacter player : affectedPlayers)
                player.ZergMultiplier = 1.0f;
        }

        public static void startZergThreadMine(Mine mine) {
            Thread zergMechanicThread = new Thread(new ZergMechanicThread(null, mine));
            zergMechanicThread.setName(mine.getParentZone().getName() + "Mine");
            zergMechanicThread.start();
        }

        public static void startZergThreadBane(Bane bane) {
            Thread zergMechanicThread = new Thread(new ZergMechanicThread(bane, null));
            zergMechanicThread.setName(bane.getCity().getGuild().getName() + "Bane");
            zergMechanicThread.start();
        }
    }
