package me.km.events;

import java.util.HashMap;
import java.util.LinkedList;
import me.hammerle.snuviscript.code.Script;
import me.km.scheduler.SnuviScheduler;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.PistonBlockStructureHelper;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.event.world.PistonEvent;
import net.minecraftforge.event.world.PistonEvent.PistonMoveType;

public class CustomEventCaller {
    private final HashMap<Integer, PlayerMoveData> moveData = new HashMap<>();

    private final LinkedList<Integer> removeQueue = new LinkedList<>();
    private final LinkedList<PlayerMoveData> addQueue = new LinkedList<>();

    private final MinecraftServer server;
    private final SnuviScheduler scheduler;

    public CustomEventCaller(MinecraftServer server, SnuviScheduler scheduler) {
        this.server = server;
        this.scheduler = scheduler;
    }

    public int registerMoveData(PlayerMoveData data) {
        addQueue.add(data);
        return data.getId();
    }

    public void removeScriptData(Script sc) {
        moveData.entrySet().forEach(e -> {
            if(e.getValue().isSameScript(sc)) {
                removeQueue.add(e.getValue().getId());
            }
        });
    }

    public void removeMoveData(int id) {
        removeQueue.add(id);
    }

    @SubscribeEvent
    public void onServerTick(TickEvent.ServerTickEvent e) {
        if(e.phase == TickEvent.Phase.END) {
            scheduler.tick();
            if(!addQueue.isEmpty()) {
                addQueue.forEach(data -> moveData.put(data.getId(), data));
                addQueue.clear();
            }
            moveData.values().removeIf(data -> {
                if(data.tickLiving()) {
                    return true;
                }
                if(data.tick()) {
                    return false;
                }
                return server.getPlayerList().getPlayers().stream().anyMatch(p -> data.check(p));
            });
            if(!removeQueue.isEmpty()) {
                removeQueue.forEach(i -> moveData.remove(i));
                removeQueue.clear();
            }
        }
    }

    @SubscribeEvent
    public void onPiston(PistonEvent.Pre e) {
        if(e.getPistonMoveType() != PistonMoveType.EXTEND) {
            return;
        }
        PistonBlockStructureHelper helper = e.getStructureHelper();
        if(helper == null) {
            return;
        }
        helper.canMove();
        for(BlockPos pos : helper.getBlocksToDestroy()) {
            BlockState state = e.getWorld().getBlockState(pos);
            Block b = state.getBlock();
            if(b == Blocks.CACTUS || b == Blocks.BAMBOO || b == Blocks.SUGAR_CANE) {
                e.getWorld().setBlockState(pos, Blocks.AIR.getDefaultState(), 3);
            }
        }
    }
}
