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.PlayerBlockBreakEvent;
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.ItemStack;
import net.minestom.server.item.Material;
import org.jetbrains.annotations.NotNull;

import java.util.concurrent.CompletableFuture;

public class Spleef extends StatelessGame {
    final int heightPerLevel = 20;
    final int totalElevation = 50;
    int radius;
    int stackCount;

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

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

        this.setGenerator(new CircularPlateTerrainGenerator(50));

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

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

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

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

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

    @Override
    protected void onStart() {
        this.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() < this.totalElevation) {
            playerMoveEvent.getPlayer().setGameMode(GameMode.SPECTATOR);
            playerMoveEvent.getPlayer().getInventory().clear();
            this.getScore().insertResult(playerMoveEvent.getPlayer());
        }
    }

    @Override
    protected void onBlockBreak(@NotNull PlayerBlockBreakEvent event) {
        if(!this.isRunning) {
            event.setCancelled(true);
            return;
        }
        this.setBlock(event.getBlockPosition(), Block.AIR);
    }

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

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