package com.skelril.aurora.city.engine.arena;

import com.sk89q.commandbook.CommandBook;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BlockID;
import com.sk89q.worldedit.bukkit.BukkitUtil;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.skelril.aurora.SacrificeComponent;
import com.skelril.aurora.events.entity.item.DropClearPulseEvent;
import com.skelril.aurora.util.ChanceUtil;
import com.skelril.aurora.util.ChatUtil;
import com.skelril.aurora.util.LocationUtil;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.Chest;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.ExperienceOrb;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitTask;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

/**
 * Author: Turtle9598
 */
public class DropPartyArena extends AbstractRegionedArena implements CommandTriggeredArena, Listener {

    private final CommandBook inst = CommandBook.inst();
    private final Logger log = inst.getLogger();
    private final Server server = CommandBook.server();

    private List<ItemStack> drops;
    private BukkitTask task = null;
    private long lastDropPulse = 0;

    public DropPartyArena(World world, ProtectedRegion region) {

        super(world, region);
        drops = new ArrayList<>();

        //noinspection AccessStaticViaInstance
        inst.registerEvents(this);
    }

    @Override
    public void run() {

        drop(1216);
    }

    @Override
    public void disable() {

        // No disabling code
    }

    @Override
    public String getId() {

        return getRegion().getId();
    }

    @Override
    public void equalize() {
        // Nothing to do
    }

    @Override
    public ArenaType getArenaType() {

        return ArenaType.COMMAND_TRIGGERED;
    }

    public void drop(int populatorValue) {

        drop(populatorValue, 12);
    }

    public void drop(int populatorValue, int modifier) {

        final boolean populate = populatorValue > 0;
        Bukkit.broadcastMessage(ChatColor.GOLD + "Drop party in 60 seconds!");

        if (populate) {
            for (int i = 0; i < server.getOnlinePlayers().length * modifier; i++) {
                // Stack of Blaze Rod equivalent
                drops.addAll(SacrificeComponent.getCalculatedLoot(server.getConsoleSender(), 64, populatorValue));
            }
        }

        if (task != null) server.getScheduler().cancelTask(task.getTaskId());

        task = server.getScheduler().runTaskTimer(inst, new Runnable() {

            @Override
            public void run() {

                if (lastDropPulse != 0 && System.currentTimeMillis() - lastDropPulse < TimeUnit.SECONDS.toMillis(3)) {
                    return;
                }

                List<ItemStack> dropped = new ArrayList<>();

                Vector min = getRegion().getMinimumPoint();
                Vector max = getRegion().getMaximumPoint();

                // Remove null drops and shuffle all other drops
                drops.removeAll(Collections.singleton(null));
                Collections.shuffle(drops);

                for (ItemStack drop : drops) {

                    if (dropped.size() > 10) break;

                    Vector v = LocationUtil.pickLocation(min.getX(), max.getX(), min.getZ(), max.getZ());
                    Location l = new Location(getWorld(), v.getX(), v.getY(), v.getZ()).add(0, max.getBlockY(), 0);
                    if (!getWorld().getChunkAt(l).isLoaded()) getWorld().getChunkAt(l).load(true);
                    getWorld().dropItem(l, drop);
                    dropped.add(drop);

                    if (populate) {
                        // Throw in some xp cause why not
                        for (short s = (short) ChanceUtil.getRandom(5); s > 0; s--) {
                            ExperienceOrb e = (ExperienceOrb) getWorld().spawnEntity(l, EntityType.EXPERIENCE_ORB);
                            e.setExperience(8);
                        }
                    }
                }

                for (ItemStack drop : dropped) {
                    if (drops.contains(drop)) drops.remove(drop);
                }

                if (drops.size() < 1) {
                    server.getScheduler().cancelTask(task.getTaskId());
                    task = null;
                }
            }
        }, 20 * 60, 20 * 3);
    }

    @EventHandler
    public void onDropClearPulse(DropClearPulseEvent event) {

        if (task != null) {
            lastDropPulse = System.currentTimeMillis();
            ChatUtil.sendNotice(getContainedPlayers(1), "Drop Party temporarily suspended for: Drop Clear.");
            for (Item item : getWorld().getEntitiesByClass(Item.class)) {
                if (getRegion().getParent().contains(BukkitUtil.toVector(item.getLocation()))) {
                    drops.add(item.getItemStack());
                    item.remove();
                }
            }
        }
    }

    @EventHandler
    public void onPlayerInteract(PlayerInteractEvent event) {

        Block block = event.getClickedBlock();

        if (event.getAction().equals(Action.RIGHT_CLICK_BLOCK) && block.getTypeId() == BlockID.STONE_BUTTON
                && getRegion().getParent().contains(new Vector(block.getX(), block.getY(), block.getZ()).floor())) {

            Player player = event.getPlayer();

            if (task != null) {

                ChatUtil.sendError(player, "There is already a drop party in progress!");
                return;
            }

            // Scan for, and absorb chest contents
            Vector min = getRegion().getParent().getMinimumPoint();
            Vector max = getRegion().getParent().getMaximumPoint();

            int minX = min.getBlockX();
            int minY = min.getBlockY();
            int minZ = min.getBlockZ();
            int maxX = max.getBlockX();
            int maxY = max.getBlockY();
            int maxZ = max.getBlockZ();

            for (int x = minX; x <= maxX; x++) {
                for (int z = minZ; z <= maxZ; z++) {
                    for (int y = minY; y <= maxY; y++) {
                        BlockState chest = getWorld().getBlockAt(x, y, z).getState();

                        if (chest instanceof Chest) {

                            Inventory chestInventory = ((Chest) chest).getBlockInventory();
                            Collections.addAll(drops, chestInventory.getContents());

                            chestInventory.clear();
                            chest.update(true);
                        }
                    }
                }
            }

            drop(0);
        }
    }
}

@@ -1608,16 +1608,56 @@
 lse = 0;
+%0A    private double dropPartyPulses = 0;
 %0A%0A    pu
@@ -2846,32 +2846,79 @@
    %7D%0A        %7D%0A%0A
+        dropPartyPulses = drops.size() * 1.5;%0A%0A
         if (task
@@ -4723,16 +4723,40 @@
 ze() %3C 1
+ %7C%7C dropPartyPulses %3C= 0
 ) %7B%0A    
@@ -4865,32 +4865,68 @@
                %7D
+%0A%0A                dropPartyPulses--;
 %0A            %7D%0A 

Make the drop parties short circuit if there are too many drop clears