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

import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game.TetrisGame;
import eu.mhsl.minenet.minigames.score.FirstWinsScore;
import eu.mhsl.minenet.minigames.instance.Dimension;
import eu.mhsl.minenet.minigames.world.generator.terrain.CircularPlateTerrainGenerator;
import net.kyori.adventure.text.Component;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.coordinate.Vec;
import net.minestom.server.entity.Player;
import net.minestom.server.event.player.*;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import org.jetbrains.annotations.NotNull;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

class Tetris extends StatelessGame {
    private TetrisGame tetrisGame;

    private final Map<Button, Long> lastPresses = new HashMap<>();

    enum Button {
        W,
        A,
        S,
        D,
        mouseLeft,
        mouseRight,
        space
    }

    public Tetris() {
        super(Dimension.THE_END.key, "Tetris", new FirstWinsScore());
        this.setGenerator(new CircularPlateTerrainGenerator(30).setPlateHeight(0));

        eventNode()
            .addListener(PlayerUseItemEvent.class, this::onPlayerInteract)
            .addListener(PlayerHandAnimationEvent.class, this::onPlayerAttack);
    }

    @Override
    protected void onStart() {
        super.onStart();

        this.tetrisGame.start();
    }

    protected void pressedButton(Button button) {
        if(lastPresses.getOrDefault(button, 0L) >= System.currentTimeMillis()-100) return;
        lastPresses.put(button, System.currentTimeMillis());

        switch (button) {
            case A -> {
                System.out.println("A");
                System.out.println(this.tetrisGame.moveLeft());
            }
            case S -> {
                System.out.println("S");
                System.out.println(this.tetrisGame.moveDown());
            }
            case D -> {
                System.out.println("D");
                System.out.println(this.tetrisGame.moveRight());
            }
            case W -> System.out.println("W");
            case mouseLeft -> {
                System.out.println("mouse left");
                System.out.println(this.tetrisGame.rotate(false));
            }
            case mouseRight -> {
                System.out.println("mouse right");
                System.out.println(this.tetrisGame.rotate(true));
            }
            case space -> System.out.println("space");
        }
    }

    protected void releasedButton(Button button) {
        lastPresses.put(button, 0L);
    }

    @Override
    protected void onLoad(@NotNull CompletableFuture<Void> callback) {
        this.tetrisGame = new TetrisGame(this, getSpawn().sub(6, 8, 15));
        this.tetrisGame.generate();
    }

    @Override
    protected void onPlayerMove(@NotNull PlayerMoveEvent event) {
        super.onPlayerMove(event);

        Player player = event.getPlayer();
        Pos previousPosition = event.getPlayer().getPosition();
        Pos currentPosition = event.getNewPosition();

        Vec movementVector = currentPosition.asVec().sub(previousPosition.asVec());

        float yaw = player.getPosition().yaw();

        double yawRadians = Math.toRadians(yaw);
        double forwardX = -Math.sin(yawRadians);
        double forwardZ = Math.cos(yawRadians);

        Vec forward = new Vec(forwardX, 0, forwardZ).normalize();
        Vec left = forward.cross(new Vec(0, 1, 0)).normalize();

        double forwardAmount = movementVector.dot(forward);
        double leftAmount = movementVector.dot(left);

        if (forwardAmount > 0.018) {
            pressedButton(Button.W);
            releasedButton(Button.S);
        } else if (forwardAmount < -0.018) {
            pressedButton(Button.S);
            releasedButton(Button.W);
        } else {
            releasedButton(Button.W);
            releasedButton(Button.S);
        }

        if (leftAmount > 0.018) {
            pressedButton(Button.D);
            releasedButton(Button.A);
        } else if (leftAmount < -0.018) {
            pressedButton(Button.A);
            releasedButton(Button.D);
        } else {
            releasedButton(Button.A);
            releasedButton(Button.D);
        }

        if(previousPosition.y() < currentPosition.y()) pressedButton(Button.space);

        event.setNewPosition(getSpawn().withView(event.getNewPosition()));
    }

    protected void onPlayerInteract(@NotNull PlayerUseItemEvent event) {
        pressedButton(Button.mouseRight);
    }

    protected void onPlayerAttack(@NotNull PlayerHandAnimationEvent event) {
        pressedButton(Button.mouseLeft);
    }

    @Override
    protected boolean onPlayerJoin(Player p) {
        p.getInventory().setItemStack(0, ItemStack.builder(Material.BIRCH_BUTTON).customName(Component.text("Controller")).build());
        p.setSprinting(false);
        return super.onPlayerJoin(p);
    }

    @Override
    public Pos getSpawn() {
        return new Pos(0, 50, 15).withView(180, 0);
    }
}
