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

import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame;
import eu.mhsl.minenet.minigames.score.FirstWinsScore;
import eu.mhsl.minenet.minigames.util.BatchUtil;
import eu.mhsl.minenet.minigames.util.CommonProperties;
import eu.mhsl.minenet.minigames.util.Intersect;
import eu.mhsl.minenet.minigames.instance.Dimension;
import eu.mhsl.minenet.minigames.world.BlockPallet;
import eu.mhsl.minenet.minigames.world.generator.terrain.SquarePlateTerrainGenerator;
import net.kyori.adventure.sound.Sound;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player;
import net.minestom.server.event.player.PlayerMoveEvent;
import net.minestom.server.instance.batch.AbsoluteBlockBatch;
import net.minestom.server.instance.block.Block;
import net.minestom.server.sound.SoundEvent;
import org.jetbrains.annotations.NotNull;

import java.util.*;
import java.util.concurrent.CompletableFuture;

class Minerun extends StatelessGame {

    private final int minePercentage;
    private final int width;
    private final int length;

    private final int preRun = 5;
    private final int afterMines = 2;
    private final int afterFinishLine = 10;

    public Minerun(int width, int length, int minePercentage) {
        super(Dimension.THE_END.key, "Minerun", new FirstWinsScore());
        setGenerator(new SquarePlateTerrainGenerator(width, length + preRun + afterFinishLine).setPlateHeight(50).setGenerateBorders(true));

        this.width = width;
        this.length = length;
        this.minePercentage = minePercentage;
    }

    @Override
    protected void onLoad(@NotNull CompletableFuture<Void> callback) {
        int spawnToFinishLine = preRun + length + afterMines;

        Random random = new Random();
        AbsoluteBlockBatch batch = new AbsoluteBlockBatch();

        for(int x = 0; x <= width; x++) {
            for(int z = preRun; z <= length + preRun; z++) {

                if (random.nextInt(0, 100) < minePercentage) {
                    batch.setBlock(x, 50, z, BlockPallet.PRESSURE_PLATES.rnd());
                }
            }
        }

        for(int x = 0; x <= width; x++) {
            batch.setBlock(x, 49, spawnToFinishLine, Block.GOLD_BLOCK);
            batch.setBlock(x, 49, preRun, Block.GOLD_BLOCK);
            batch.setBlock(x, 50, preRun, Block.OAK_FENCE.withProperties(CommonProperties.fenceEastWest));
        }
        BatchUtil.loadAndApplyBatch(batch, this, () -> callback.complete(null));
    }

    @Override
    protected void onStart() {
        AbsoluteBlockBatch batch = new AbsoluteBlockBatch();
        for(int x = 0; x <= width; x++) {
            batch.setBlock(x, 50, preRun, Block.AIR);
        }

        BatchUtil.loadAndApplyBatch(batch, this, () -> playSound(Sound.sound(SoundEvent.BLOCK_WOOD_BREAK, Sound.Source.BLOCK, 1f, 1f)));
    }

    @Override
    protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) {

        Player p = playerMoveEvent.getPlayer();
        Pos middle = playerMoveEvent.getNewPosition();

        if(isBeforeBeginning && middle.z() > preRun+0.5) { //player cannot go forward before the game start
            playerMoveEvent.setCancelled(true);
        }

        if(Intersect.withPressurePlate(this, BlockPallet.PRESSURE_PLATES, middle)) { //Player died
            p.playSound(Sound.sound(SoundEvent.ENTITY_GENERIC_EXPLODE, Sound.Source.PLAYER, 1f, 1f));
            p.teleport(new Pos(p.getPosition().x(), getSpawn().y(), getSpawn().z()));
        }

        if(middle.z() > preRun + length + afterMines) { // Player finished
            getScore().insertResult(p);
            p.setGameMode(GameMode.SPECTATOR);
        }
    }

    @Override
    public Pos getSpawn() {
        return new Pos((double) width /2, 50, 3);
    }
}
