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

import eu.mhsl.minenet.minigames.instance.game.Game;
import eu.mhsl.minenet.minigames.message.Countdown;
import eu.mhsl.minenet.minigames.message.Icon;
import eu.mhsl.minenet.minigames.message.type.ChatMessage;
import eu.mhsl.minenet.minigames.message.type.TitleMessage;
import eu.mhsl.minenet.minigames.score.Score;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.registry.DynamicRegistry;
import net.minestom.server.timer.ExecutionType;
import net.minestom.server.timer.Task;
import net.minestom.server.timer.TaskSchedule;
import net.minestom.server.world.DimensionType;

import java.time.Duration;
import java.util.concurrent.CompletableFuture;

public class StatelessGame extends Game {
    private final String name;
    private final Score score;
    private Task timeLimitTask;

    private int timeLimit = 0;
    private int timePlayed = 0;

    public StatelessGame(DynamicRegistry.Key<DimensionType> dimensionType, String gameName, Score score) {
        super(dimensionType);
        this.score = score;
        this.name = gameName;
    }

    public Score getScore() {
        return this.score;
    }

    public String getName() {
        return this.name;
    }

    public void setTimeLimit(int limit) {
        this.timeLimit = limit;
        if(this.timeLimitTask != null) {
            this.timeLimitTask.cancel();
            this.timePlayed = 0;
        }
        if(this.timeLimit > 0) {
            this.timeLimitTask = this.scheduler().submitTask(() -> {
                if(!this.isRunning || this.timeLimit == 0) return TaskSchedule.stop();
                if(this.timeLimit <= this.timePlayed) {
                    this.stop();
                    return TaskSchedule.stop();
                }

                int timeLeft = this.timeLimit - this.timePlayed;
                switch(timeLeft) {
                    case 90, 60, 30, 10, 5, 4, 3, 2, 1 -> new ChatMessage(Icon.TIME)
                        .appendStatic(String.valueOf(timeLeft))
                        .appendSpace()
                        .appendTranslated(timeLeft == 1 ? "common#secondsLeft_singular" : "common#secondsLeft_plural")
                        .send(this.getPlayers());
                }

                this.timePlayed++;

                return TaskSchedule.seconds(1);
            }, ExecutionType.TICK_START);
        }
    }

    @Override
    public void load() {
        super.load();
    }

    /**
     * Displays countdown and starts the game
     * When overriding make sure to call this::start after countdown!
     */
    protected CompletableFuture<Void> countdownStart() {
        Duration fadeIn = Duration.ofMillis(300);
        Duration stay = Duration.ofMillis(700);

        return new Countdown()
            .countdown(
                Audience.audience(this.getPlayers()),
                5,
                modifier -> modifier.message = new TitleMessage(fadeIn, stay)
                    .subtitle(subtitleMessage -> subtitleMessage
                        .appendTranslated("common#startIn", NamedTextColor.DARK_GREEN)
                        .appendSpace()
                        .appendStatic(Component.text(modifier.timeLeft, NamedTextColor.GREEN))
                        .appendSpace()
                        .appendTranslated(modifier.timeLeft == 1 ? "common#second" : "common#seconds", NamedTextColor.DARK_GREEN)
                    )
            );
    }

    public void startAccessor() {
        this.start();
    }

    @Override
    protected void start() {
        this.score.setInstance(this);
        this.score.attachListeners();

        this.countdownStart().thenRun(super::start);
    }

    @Override
    public void stop() {
        this.isRunning = false;
        this.onStop();
        this.getScore().insertRemainingPlayers(this.getPlayers());
        this.publishScore(this.getScore());

        this.countdownUnload();
    }

    private void countdownUnload() {
        new TitleMessage(Duration.ofSeconds(1)).appendTranslated("score#done").send(this.getPlayers());
        this.scheduler().scheduleTask(this::unload, TaskSchedule.seconds(5), TaskSchedule.stop());
    }
}
