package eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.enemies;

import eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.Towerdefense;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.EntityType;
import net.minestom.server.timer.TaskSchedule;

import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicInteger;

public class WaveGenerator {
    final Towerdefense game;
    int currentLevel;
    Random random = new Random();
    private final Map<EnemyFactory, Integer> availableEnemies = Map.of(
        new EnemyFactory(EntityType.PIG, 2, 0.1), new EnemyFactory(EntityType.PIG, 2, 0.1).getStrength(),
        new EnemyFactory(EntityType.VILLAGER, 6, 0.1), new EnemyFactory(EntityType.VILLAGER, 6, 0.1).getStrength(),
        new EnemyFactory(EntityType.SHEEP, 4, 0.2), new EnemyFactory(EntityType.SHEEP, 4, 0.2).getStrength(),
        new EnemyFactory(EntityType.COW, 10, 0.1), new EnemyFactory(EntityType.COW, 10, 0.1).getStrength(),
        new EnemyFactory(EntityType.CAMEL, 10, 0.2), new EnemyFactory(EntityType.CAMEL, 10, 0.2).getStrength(),
        new EnemyFactory(EntityType.ARMADILLO, 20, 0.4), new EnemyFactory(EntityType.ARMADILLO, 20, 0.3).getStrength(),
        new EnemyFactory(EntityType.CHICKEN, 8, 0.5), new EnemyFactory(EntityType.CHICKEN, 8, 0.6).getStrength()
    );

    public WaveGenerator(Towerdefense game) {
        this(game, 1);
    }

    public WaveGenerator(Towerdefense game, int startLevel) {
        this.game = game;
        this.currentLevel = startLevel - 1;
    }

    public void startNextWave() {
        this.currentLevel += 1;
        List<EnemyFactory> enemyList = this.chooseEnemies();
        Collections.shuffle(enemyList);

        int averageDelay = Math.min(20000 / enemyList.size(), 1500);
        AtomicInteger delay = new AtomicInteger(0);
        enemyList.forEach(enemy -> {
            delay.addAndGet(averageDelay);
            MinecraftServer.getSchedulerManager().scheduleTask(
                () -> this.spawnEnemy(enemyList.removeFirst()),
                TaskSchedule.millis(delay.get() + this.random.nextInt(averageDelay-200, averageDelay+200)),
                TaskSchedule.stop()
            );
        });
    }

    private void spawnEnemy(EnemyFactory enemy) {
        this.game.getInstances().forEach(instance -> instance.addEnemy(enemy.buildEntity()));
    }

    private int getCurrentLevelStrength() {
        return (int) (0.5 * Math.pow(2, this.currentLevel));
    }

    private List<EnemyFactory> chooseEnemies() {
        int strength = this.getCurrentLevelStrength();
        final List<EnemyFactory> usedEnemies = new ArrayList<>();

        while(strength > 0) {
            int finalStrength = strength;
            Map.Entry<EnemyFactory, Integer> chosenEnemy = this.availableEnemies.entrySet().stream()
                .filter(e -> e.getValue() <= finalStrength)
                .sorted((o1, o2) -> ThreadLocalRandom.current().nextInt(-1, 2))
                .findAny()
                .get();
            usedEnemies.add(chosenEnemy.getKey());
            strength -= chosenEnemy.getKey().getStrength();
        }

        return usedEnemies;
    }
}
