package eu.midnightdust.yaytris.game;

import eu.midnightdust.yaytris.Tetris;
import eu.midnightdust.yaytris.util.SoundEffect;

import java.awt.Color;
import java.util.*;

import static eu.midnightdust.yaytris.Tetris.random;

public class Space {
    private final Color[][] gameMap; // Bereits abgesetzte Tetrominos werden nur noch als einzelne Farben ('Blobs') auf der Karte abgespeichert
    private TetrominoShape nextShape;
    private Tetromino currentTetromino;
    private int score;
    public int level;

    public Space() {
        gameMap = new Color[14][8];
        nextShape = generateNextShape();
        score = 0;
    }

    public void spawnTetromino() {
        currentTetromino = new Tetromino(nextShape);
        nextShape = generateNextShape();
    }

    public Tetromino getCurrentTetromino() {
        return currentTetromino;
    }

    public TetrominoShape generateNextShape() {
        return TetrominoShape.values()[random.nextInt(TetrominoShape.values().length)];
    }

    public TetrominoShape getNextShape() {
        return nextShape;
    }

    public int getMapWidth() {
        return gameMap[0].length;
    }

    public int getMapHeight() {
        return gameMap.length;
    }

    public Color[][] getGameMapWithTetromino() {
        Color[][] tempGameMap = new Color[gameMap.length][gameMap[0].length];
        for (int y = 0; y < tempGameMap.length; y++) {
            System.arraycopy(gameMap[y], 0, tempGameMap[y], 0, tempGameMap[y].length);
            if (currentTetromino == null) continue;
            Color[] newBlobs = currentTetromino.getLine(y);
            for (int i = 0; i < newBlobs.length; i++) {
                if (newBlobs[i] == null) continue;
                tempGameMap[y][i] = newBlobs[i];
            }
        }

        return tempGameMap;
    }

    public Color[][] getGameMap() {
        return gameMap;
    }

    public int getScore() {
        return score;
    }

    public void onLinesChanged(Tetromino tetromino, int... lines) {
        int combo = 0;
        Set<Integer> completedLines = new TreeSet<>();
        for (int line : lines) {
            if (line >= getMapHeight()) continue;
            if (line < 0) {
                Tetris.stopGame();
                return;
            }
            Color[] newBlobs = tetromino.getLine(line);
            for (int i = 0; i < newBlobs.length; i++) {
                if (newBlobs[i] == null) continue;
                gameMap[line][i] = newBlobs[i];
            }
            if (Arrays.stream(gameMap[line]).noneMatch(Objects::isNull)) { // Line completed
                combo += 40;
                completedLines.add(line);
                combo *= completedLines.size();
            }
        }
        if (!completedLines.isEmpty()) SoundEffect.LINE_COMPLETED.play();
        for (int completedIndex = 0; completedIndex < completedLines.size(); completedIndex++) { // Remove completed lines
            int line = completedLines.toArray(new Integer[0])[completedIndex];
            for (int i = line; i >= 0; i--) {
                gameMap[i] = (i-1 < 0) ? new Color[gameMap[i].length] : gameMap[i-1];
            }
        }
        increaseScore(combo);
        this.spawnTetromino();
    }

    public void increaseScore(int amount) {
        this.score += amount;
        Tetris.updateScore(this.score);
    }
}
