package com.agineek.agineek_pad_plugin

import android.util.Log
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.locks.Lock
import java.util.concurrent.locks.ReentrantLock
// import kotlin.collections.ArrayList

@kotlin.ExperimentalStdlibApi
class Game(
    private val sequence: PadSequence,
    private var gameTime: Long,
    private var padLightUpTime: Int = 0,
    private var padLightUpTimeDelay: Int = 0
) : Thread() {
    companion object {
        @JvmStatic
        val Tag = "Game"
        @JvmStatic
        val gameOver = AtomicBoolean(false)
    }

    public var isHit: Boolean = false
    public var isSleeping: Boolean = false
    public var byHits: Boolean = false
    public var lightUpTime: Long
//        get() {
//            if (isSleeping) {
//                Log.d(Tag, "We are getting time while sleeping.")
//            }
//            return lightUpTime
//        }
//        set(time: Long) {
//            Log.d(Tag, "time is ${time}")
//            lightUpTime = time
//        }
    private var count: Int = 0
    private var lock: ReentrantLock = ReentrantLock()
    private lateinit var playGameThread: Thread

    init {
        lightUpTime = 0L
    }

    override fun interrupt() {
        gameOver.set(true)
        super.interrupt()
        for (pad in sequence.pads) { // TODO: is the iterator supposed to be a tuple (_, pad)?
            pad.turnOff()
            pad.endGame()
            Log.d(Tag, "Sending game over...")
        }
    }

    override fun run() {
        Log.d(Tag, "At the start of run")
        gameOver.set(false)
        for (pad in sequence.pads) {
            pad.turnOff()
            pad.startGame()
            Log.d(Tag, "Pad: ${pad.uuid} has started the game.")
        }

        val startTime = System.currentTimeMillis()

        if (byHits) {
            while (!Thread.currentThread().isInterrupted) {
                playGame(startTime)
            }

            Thread.currentThread().interrupt()
        } else {
            val currentTime = System.currentTimeMillis() - startTime

            while (gameTime > currentTime && !Thread.currentThread().isInterrupted) {
                playGame(startTime)
            }
        }
    }

    private fun playGame(startTime: Long) {
        Log.d(Tag, "Called playGame()")
        lock.lock()
        count++
        isHit = false

        isSleeping = true
        sequence.next()
        lightUpTime = System.currentTimeMillis()
        Log.d(Tag, "lightUpTime: $lightUpTime")

        isSleeping = false

        if (padLightUpTime != 0) {
            var time: Int = 0

            while (padLightUpTime > (System.currentTimeMillis() - lightUpTime) && !isHit && !Thread.currentThread().isInterrupted) {

                if (!(gameTime > System.currentTimeMillis() - startTime) && !Thread.currentThread().isInterrupted && !byHits) {
                    Thread.currentThread().interrupt()
                }
            }

            isSleeping = true

            if (!isHit) {
                Log.d(Tag, "Failed to get a hit")
                for (player: Player in sequence.players) {
                    player.addMiss(currentTime = 2, padId = sequence.currentLitPad!!.uuid) // TODO: add currentTime parameter for this function
                    player.removePoints()
                }
                sequence.currentLitPad?.turnOff()
            }

        } else {
            while (!isHit) {
                if (!(gameTime > System.currentTimeMillis() - startTime) && !Thread.currentThread().isInterrupted && !byHits) {
                    Thread.currentThread().isInterrupted
                }
            }
        }

        if (sequence.nextPad != null) {
            sequence.nextPad!!.turnOff()
        }

        if (padLightUpTime != 0) {
            var startLightUpDelayTime: Long = System.currentTimeMillis()
            while (padLightUpTimeDelay > System.currentTimeMillis() - startLightUpDelayTime) {
                if (!(gameTime > System.currentTimeMillis() - startTime) && !Thread.currentThread().isInterrupted && !byHits) {
                    Thread.currentThread().interrupt()
                }
            }
        }

        isSleeping = false
        lock.unlock()
    }
}
