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

import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame;
import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.timer.Scheduler;
import net.minestom.server.timer.TaskSchedule;

import java.util.Random;

public class TetrisGame {
    private final StatelessGame instance;
    private final Playfield playfield;
    private int level = 1;
    private int lines = 0;
    private int score = 0;
    private boolean lost = false;
    public Tetromino currentTetromino;
    private Tetromino nextTetromino;
    private Tetromino holdTetromino;
    private final Random random = new Random();

    private final Pos tetrominoSpawnPosition;

    public TetrisGame(StatelessGame instance, Pos lowerLeftCorner) {
        this(instance, lowerLeftCorner, new Tetromino(instance, Tetromino.Shape.J), new Tetromino(instance, Tetromino.Shape.T));
    }

    public TetrisGame(StatelessGame instance, Pos lowerLeftCorner, Tetromino startTetromino, Tetromino nextTetromino) {
        this.instance = instance;
        this.playfield = new Playfield(lowerLeftCorner, this.instance);
        this.currentTetromino = startTetromino;
        this.nextTetromino = nextTetromino;

        this.tetrominoSpawnPosition = this.playfield.getTetrominoSpawnPosition();
    }

    public void start() {
        Scheduler scheduler = MinecraftServer.getSchedulerManager();
        scheduler.submitTask(() -> {
            if(this.lost) return TaskSchedule.stop();
            this.tick();
            return TaskSchedule.tick(40/this.level);
        });
    }

    public void generate() {
        this.playfield.generate();

        this.currentTetromino.setPosition(this.tetrominoSpawnPosition);
        this.currentTetromino.draw();
    }

    public void tick() {
        if(this.lost) return;
        if(!currentTetromino.moveDown()) {
            setActiveTetrominoDown();
        }
    }


    public boolean rotate(boolean clockwise) {
        if(this.lost) return false;
        return this.currentTetromino.rotate(clockwise);
    }

    public boolean moveLeft() {
        if(this.lost) return false;
        return this.currentTetromino.moveLeft();
    }

    public boolean moveRight() {
        if(this.lost) return false;
        return this.currentTetromino.moveRight();
    }

    public boolean moveDown() {
        if(this.lost) return false;
        if(!this.currentTetromino.moveDown()) {
            this.setActiveTetrominoDown();
            return false;
        }
        this.score += 1;
        return true;
    }


    private Tetromino getNextTetromino() {
        int randomNumber = random.nextInt(1, 7);
        Tetromino.Shape nextShape;

        switch (randomNumber) {
            case 2 -> nextShape = Tetromino.Shape.J;
            case 3 -> nextShape = Tetromino.Shape.L;
            case 4 -> nextShape = Tetromino.Shape.O;
            case 5 -> nextShape = Tetromino.Shape.S;
            case 6 -> nextShape = Tetromino.Shape.T;
            case 7 -> nextShape = Tetromino.Shape.Z;
            default -> nextShape = Tetromino.Shape.I;
        }

        return new Tetromino(this.instance, nextShape);
    }

    private void loose() {
        this.lost = true;
    }

    private void setActiveTetrominoDown() {
        currentTetromino = nextTetromino;
        nextTetromino = getNextTetromino();

        int removedLines = this.playfield.removeFullLines();
        switch (removedLines) {
            case 1 -> {
                this.lines += 1;
                this.score += 40 * this.level;
            }
            case 2 -> {
                this.lines += 3;
                this.score += 100 * this.level;
            }
            case 3 -> {
                this.lines += 5;
                this.score += 300 * this.level;
            }
            case 4 -> {
                this.lines += 8;
                this.score += 1200 * this.level;
            }
        }

        currentTetromino.setPosition(this.tetrominoSpawnPosition);
        currentTetromino.draw();
        if(!currentTetromino.moveDown()) {
            loose();
        }
    }
}
