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

import eu.mhsl.minenet.minigames.instance.Dimension;
import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame;
import eu.mhsl.minenet.minigames.score.LastWinsScore;
import eu.mhsl.minenet.minigames.world.generator.terrain.CircularPlateTerrainGenerator;
import io.github.togar2.pvp.events.FinalAttackEvent;
import io.github.togar2.pvp.feature.CombatFeatures;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Player;
import net.minestom.server.event.player.PlayerMoveEvent;
import net.minestom.server.instance.block.Block;
import org.jetbrains.annotations.NotNull;

import java.util.List;
import java.util.WeakHashMap;
import java.util.concurrent.CompletableFuture;

public class Stickfight extends StatelessGame {
    private final double radius = 20;
    private final WeakHashMap<Player, Pos> spawnPoints = new WeakHashMap<>();

    public Stickfight() {
        super(Dimension.OVERWORLD.key, "Stickfight", new LastWinsScore());

        eventNode().addChild(
            CombatFeatures.empty()
                .add(CombatFeatures.VANILLA_ATTACK)
                .add(CombatFeatures.VANILLA_DAMAGE)
                .add(CombatFeatures.VANILLA_KNOCKBACK)
                .build().createNode()
        );

        eventNode().addListener(FinalAttackEvent.class, finalAttackEvent -> {
            finalAttackEvent.setBaseDamage(0);
            ((Player) finalAttackEvent.getTarget()).setHealth(20);
        });

        setGenerator(new CircularPlateTerrainGenerator(20));
    }

    @Override
    protected void onLoad(@NotNull CompletableFuture<Void> callback) {
        setBlock(0, 50, 0, Block.DIAMOND_BLOCK);
    }

    @Override
    protected void start() {
        List<Player> players = getPlayers().stream().toList();
        int numPlayers = players.size();

        for (int i = 0; i < numPlayers; i++) {
            double angle = (2 * Math.PI / numPlayers) * i;
            int spawnX = (int) (radius * Math.cos(angle));
            int spawnZ = (int) (radius * Math.sin(angle));
            int spawnY = 50;

            Pos spawnpoint = new Pos(spawnX, spawnY + 1, spawnZ).add(0.5);
            spawnPoints.put(players.get(i), spawnpoint.withLookAt(getSpawn()));
            players.get(i).teleport(spawnpoint);

            generateBridge(spawnX, spawnY, spawnZ);
        }

        setBlock(0, 50, 0, Block.GOLD_BLOCK);
        super.start();
    }

    private void generateBridge(int startX, int startY, int startZ) {
        int steps = (int) (radius * 1.5);
        for (int i = 0; i < steps; i++) {
            double t = (double) i / steps;
            int x = (int) (startX * (1 - t));
            int z = (int) (startZ * (1 - t));
            setBlock(x, startY, z, Block.SANDSTONE);
        }
    }

    @Override
    protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) {
        if(!spawnPoints.containsKey(playerMoveEvent.getPlayer())) {
            playerMoveEvent.setCancelled(true);
            return;
        }

        if(isBeforeBeginning) {
            if(spawnPoints.get(playerMoveEvent.getPlayer()).distance(playerMoveEvent.getNewPosition()) < 1) return;
            playerMoveEvent.setCancelled(true);
            playerMoveEvent.getPlayer().teleport(spawnPoints.get(playerMoveEvent.getPlayer()));
        }

        if(playerMoveEvent.getNewPosition().y() < 40) {
            playerMoveEvent.getPlayer().teleport(spawnPoints.get(playerMoveEvent.getPlayer()));
        }
    }

    @Override
    public Pos getSpawn() {
        return new Pos(0.5, 51, 0.5);
    }
}
