package eu.mhsl.minenet.minigames.instance.game.stateless.types.spleef;

import eu.mhsl.minenet.minigames.instance.Dimension;
import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame;
import eu.mhsl.minenet.minigames.message.component.TranslatedComponent;
import eu.mhsl.minenet.minigames.score.LastWinsScore;
import eu.mhsl.minenet.minigames.util.BatchUtil;
import eu.mhsl.minenet.minigames.world.BlockPallet;
import eu.mhsl.minenet.minigames.world.generator.terrain.CircularPlateTerrainGenerator;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.GameMode;
import net.minestom.server.event.player.PlayerMoveEvent;
import net.minestom.server.event.player.PlayerStartDiggingEvent;
import net.minestom.server.instance.batch.AbsoluteBlockBatch;
import net.minestom.server.instance.block.Block;
import net.minestom.server.item.*;
import org.jetbrains.annotations.NotNull;

import java.util.concurrent.CompletableFuture;

public class Spleef extends StatelessGame {
    int radius;
    int stackCount;

    final int heightPerLevel = 20;
    final int totalElevation = 50;

    public Spleef(int radius, int stackCount) {
        super(Dimension.OVERWORLD.key, "Spleef", new LastWinsScore());
        getScore().setIgnoreLastPlayers(1);

        this.radius = radius;
        this.stackCount = stackCount;

        setGenerator(new CircularPlateTerrainGenerator(50));

        eventNode().addListener(PlayerStartDiggingEvent.class, this::destroyBlock);
    }

    @Override
    protected void onLoad(@NotNull CompletableFuture<Void> callback) {
        AbsoluteBlockBatch circle = new AbsoluteBlockBatch();

        for (int level = 0; level < stackCount; level++) {
            for(int x = -radius; x <= radius; x++) {
                for(int z = -radius; z <= radius; z++) {
                    if(new Pos(x, 0, z).distance(new Pos(0, 0, 0)) > radius) continue;

                    circle.setBlock(x, totalElevation + (level * heightPerLevel), z, BlockPallet.WINTER.rnd());
                }
            }
        }

        BatchUtil.loadAndApplyBatch(circle, this, () -> callback.complete(null));
    }

    @Override
    protected void onStart() {
        getPlayers().forEach(player -> {
            player.setGameMode(GameMode.SURVIVAL);
            player.getInventory().addItemStack(
                    ItemStack
                            .builder(Material.DIAMOND_SHOVEL)
                            .customName(TranslatedComponent.byId("game_Spleef#shovelName").getAssembled(player))
                            .build()
            );
            player.setHeldItemSlot((byte) 0);
        });
    }

    @Override
    protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) {
        if(playerMoveEvent.getNewPosition().y() < totalElevation) {
            playerMoveEvent.getPlayer().setGameMode(GameMode.SPECTATOR);
            playerMoveEvent.getPlayer().getInventory().clear();
            getScore().insertResult(playerMoveEvent.getPlayer());
        }
    }

    private void destroyBlock(PlayerStartDiggingEvent event) {
        if(!isRunning) return;
        setBlock(event.getBlockPosition(), Block.AIR);
    }

    @Override
    public Pos getSpawn() {
        return new Pos(0, totalElevation + heightPerLevel * (stackCount-1) + 1, 0);
    }
}
