package modele

import android.util.Log
import kotlinx.coroutines.delay
import views.ViewsGame
import kotlin.io.path.fileVisitor

class DashBoard(private val width: Int,private val height: Int,private val view: ViewsGame) {
    private val gridOfGame = Array(this.height) { IntArray(this.width) }

    // To set something to occupied
    fun toOccupied(col: Int, row: Int, value: Int) {
        gridOfGame[row][col] = value
    }

    // To check if an position is occupied
    fun isOccupied(col: Int, row: Int): Boolean = gridOfGame[row][col] != 0

    private fun isLineFull(row: Int): Boolean {
        for (col in 0 until this.width) {
            if (gridOfGame[row][col] == 0) {
                return false
            }
        }
        return true
    }

    private fun clearLine(row: Int) {
        for (col in 0 until this.width) {
            gridOfGame[row][col] = 0
        }
    }

    private fun shiftDown(listeLine:MutableList<Int>) {
        Log.println(Log.DEBUG,"ActionDashborad","Shift Down !")

        for( index in listeLine){
            println(index)
            for ( line in index downTo 1 ){
                for ( column in 0 until width){
                    gridOfGame[line][column] = gridOfGame[line-1][column]
                }
            }
        }
        updateViewGame()
    }

    //To check each grid line and remove if a line is full. Uses clearLine(), isLineFull() and shiftDown()
    fun clearLines():Int{
        val listeLine = mutableListOf<Int>()
        var nbRowCleared: Int = 0
        for (row in 0 until this.height) {
            if (isLineFull(row)) {
                clearLine(row)
                ++nbRowCleared
                listeLine.add(row)
            }
        }
        if (nbRowCleared != 0) {
            shiftDown(listeLine)
        }
        return nbRowCleared
    }

    fun addShape(shape: Shape): Boolean {

        for (line in 0..3) { // On vérifie que l'espace est disponible
            for (column in 0..3) {
                if ( (shape.typeShape.showShape[line][column] == 1) and (gridOfGame[shape.position.y+line][shape.position.x+column] != 0)){
                    return false
                }
            }
        }
        writeShape(shape)
        return true
    }

    // Test si c'est possible de l'intégré dans gridOfGame
    private fun moveRightPossible(shape: Shape):Boolean{

        val pos:MutableList<Position> = shape.sharePositionRight()

        for ( position in pos){
            if ( position.x+shape.position.x >= width){
                return false
            }
            if( gridOfGame[position.y+shape.position.y][position.x+shape.position.x] != 0) {
                return false
            }
        }
        return true
    }

    fun moveRight(shape: Shape):Boolean{
        println("Shape action -> Move Right ! ")
        shape.position.addX()
        if (!moveRightPossible(shape)){
            shape.position.decrementeX()
            return false
        }
        shape.position.decrementeX()
        deleteShape(shape)
        shape.position.addX()
        writeShape(shape)
        return true
    }

    // Test si c'est possible de l'intégré dans gridOfGame
    private fun moveLeftPossible(shape: Shape):Boolean{
        val pos:MutableList<Position> = shape.sharePositionLeft()

        for ( position in pos){
            if ( shape.position.x < 0 ){
                return false
            }
            if( gridOfGame[position.y+shape.position.y][position.x+shape.position.x] != 0) {
                return false
            }
        }
        return true
    }

    fun moveLeft(shape:Shape):Boolean{
        Log.println(Log.DEBUG,"ActionShape","Move Left !")
        shape.position.decrementeX()
        if (!moveLeftPossible(shape)){
            shape.position.addX()
            return false
        }
        shape.position.addX()
        deleteShape(shape)
        shape.position.decrementeX()
        writeShape(shape)
        return true
    }
    private fun moveDownPossible(shape: Shape):Boolean{

        val pos:MutableList<Position> = shape.sharePositionDown(shape)

        for ( position in pos){
            if ( position.y+shape.position.y >= height){
                return false
            }
            if( gridOfGame[position.y+shape.position.y][position.x+shape.position.x] != 0) {
                return false
            }
        }
        return true
    }

    fun moveDown(shape: Shape):Boolean{
        Log.println(Log.DEBUG,"ActionShape","Move down !")
        shape.position.addY()
        if (!moveDownPossible(shape)){
            shape.position.decrementeY()
            return false
        }
        shape.position.decrementeY()
        deleteShape(shape)
        shape.position.addY()
        writeShape(shape)
        return true
    }

    private fun rotationShapePossible(shape: Shape,rotation:Int):Boolean{
        val matrix:Array<IntArray> = if ( rotation == 0){
            shape.sharePositionRotationRight(shape)
        } else {
            shape.sharePositionRotationLeft(shape)
        }

        for ( line in 0..3){
            for ( column in 0..3){
                if ( matrix[line][column] == 1){
                    if ( (shape.position.y+line >= height) or (shape.position.x+column >= width)){
                        return false
                    }
                    if (gridOfGame[shape.position.y+line][shape.position.x+column] != 0 ){
                        return false
                    }
                }
            }
        }
        shape.typeShape.showShape = matrix
        return true
    }


    fun rotateShapeRight(shape: Shape){
        Log.println(Log.DEBUG,"ActionShape","Rotation right !")

        deleteShape(shape)
        rotationShapePossible(shape,0)
        writeShape(shape)
    }


    fun rotateShapeLeft(shape: Shape){
        Log.println(Log.DEBUG,"ActionShape","Rotation left !")

        deleteShape(shape)
        rotationShapePossible(shape,1)
        writeShape(shape)
    }

    // Delete a shape in gridOfGame
    private fun deleteShape(shape: Shape){
        for (line in 0..3) {
            for (column in 0..3) {
                if (shape.typeShape.showShape[line][column] == 1) {
                    gridOfGame[shape.position.y + line][shape.position.x + column] = 0
                }
            }
        }
    }



    // Write the shape in gridOfGame
    private fun writeShape(shape: Shape){

        for (line in 0..3) {
            for (column in 0..3) {
                if (shape.typeShape.showShape[line][column] == 1) {
                    gridOfGame[shape.position.y+ line][shape.position.x + column] =
                        shape.typeShape.couleur
                }
            }
        }
        updateViewGame()
    }

    // Update the view
    fun updateViewGame(){
        view.tableau = gridOfGame
        view.invalidate()
    }

    suspend fun fallingShape(shape: Shape, difficulty: Difficulty):Boolean{
        when(difficulty){
            Difficulty.EASY -> delay(700)
            Difficulty.MEDIUM -> delay(500)
            Difficulty.HARD -> delay(200)
        }
        return moveDown(shape)
    }
}