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

import eu.mhsl.minenet.minigames.instance.Dimension;
import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame;
import eu.mhsl.minenet.minigames.score.LastWinsScore;
import io.github.togar2.pvp.events.FinalAttackEvent;
import io.github.togar2.pvp.events.PrepareAttackEvent;
import io.github.togar2.pvp.feature.CombatFeatures;
import net.minestom.server.MinecraftServer;
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.block.Block;
import net.minestom.server.timer.TaskSchedule;
import org.jetbrains.annotations.NotNull;

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

public class Sumo extends StatelessGame {
    int radius;
    int health;
    int seconds;

    int originalRadius;
    int timer;

    WeakHashMap<Player, Integer> healthMap = new WeakHashMap<>();

    public Sumo(int radius, int health, int seconds) {
        super(Dimension.OVERWORLD.key, "Sumo", new LastWinsScore());
        this.getScore().setIgnoreLastPlayers(1);
        this.setTime(6000);
        this.setTimeRate(0);

        this.radius = radius;
        this.health = health;
        this.seconds = seconds;

        this.originalRadius = radius;
        this.timer = seconds;

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

        this.eventNode().addListener(PrepareAttackEvent.class, prepareAttackEvent -> {
            if (this.isBeforeBeginning)
                prepareAttackEvent.setCancelled(true);
        });

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

    @Override
    protected void start() {
        this.getPlayers().forEach(player -> {
            this.healthMap.put(player, this.health);
            player.setLevel(this.healthMap.get(player));
        });

        MinecraftServer.getSchedulerManager().scheduleTask(
            () -> {
                if(this.isBeforeBeginning) return TaskSchedule.seconds(1);
                this.timer--;
                double percent = (double) this.timer / this.seconds;
                int radius = (int) (this.originalRadius * percent);
                if (this.radius >= 5) {
                    this.radius = radius;
                    this.generatePlatform();
                    return TaskSchedule.seconds(1);
                }

                return TaskSchedule.stop();
            },
            TaskSchedule.seconds(1)
        );

        super.start();
    }

    @Override
    protected void onLoad(@NotNull CompletableFuture<Void> callback) {
        this.generatePlatform();
    }

    private void generatePlatform() {
        int buffer = 5;
        for(int x = -this.radius - buffer; x <= this.radius + buffer; x++) {
            for(int z = -this.radius - buffer; z <= this.radius + buffer; z++) {
                double distance = new Pos(x, 0, z).distance(new Pos(0, 0, 0));
                if(distance <= this.radius) {
                    boolean isEdge = this.radius - 1 < distance;
                    this.setBlock(x, 0, z, isEdge ? Block.RED_CONCRETE : Block.WHITE_CONCRETE);
                } else {
                    this.setBlock(x, 0, z, Block.AIR);
                }
            }
        }
    }

    @Override
    protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) {
        Player player = playerMoveEvent.getPlayer();
        if(playerMoveEvent.getNewPosition().y() < -10) {
            player.teleport(this.getSpawn());
            this.healthMap.put(player, this.healthMap.get(player) - 1);
            player.setLevel(this.healthMap.get(player));
            if (this.healthMap.get(player) == 0) {
                this.getScore().insertResult(player);
                player.setGameMode(GameMode.SPECTATOR);
            }
        }
    }

    @Override
    public Pos getSpawn() {
        return  new Pos(0, 2, 0);
    }
}
