package lc.background

import lc.database.Statements
import java.util.concurrent.{ScheduledThreadPoolExecutor, TimeUnit}
import lc.core.{CaptchaManager, Config}
import lc.core.{Parameters, Size}
import lc.misc.HelperFunctions

class BackgroundTask(config: Config, captchaManager: CaptchaManager) {

  private val task = new Runnable {
    def run(): Unit = {
      try {
        val mapIdGCPstmt = Statements.tlStmts.get.mapIdGCPstmt
        mapIdGCPstmt.setInt(1, config.captchaExpiryTimeLimit)
        mapIdGCPstmt.executeUpdate()

        val challengeGCPstmt = Statements.tlStmts.get.challengeGCPstmt
        challengeGCPstmt.executeUpdate()

        val allCombinations = allParameterCombinations()
        val requiredCountPerCombination = Math.max(1, (config.bufferCount * 1.01) / allCombinations.size).toInt

        for (param <- allCombinations) {
          if (!shutdownInProgress) {
            val countExisting = captchaManager.getCount(param).getOrElse(0)
            val countRequired = requiredCountPerCombination - countExisting
            if (countRequired > 0) {
              val countCreate = Math.min(1.0 + requiredCountPerCombination / 10.0, countRequired).toInt
              println(s"Creating $countCreate of $countRequired captchas for $param")

              for (i <- 0 until countCreate) {
                if (!shutdownInProgress) {
                  captchaManager.generateChallenge(param)
                }
              }
            }
          }
        }
      } catch { case exception: Exception => println(exception) }
    }
  }

  private def allParameterCombinations(): List[Parameters] = {
    (config.captchaConfig).flatMap { captcha =>
      (captcha.allowedLevels).flatMap { level =>
        (captcha.allowedMedia).flatMap { media =>
          (captcha.allowedInputType).flatMap { inputType =>
            (captcha.allowedSizes).map { size =>
              Parameters(level, media, inputType, size)
            }
          }
        }
      }
    }
  }

  private def getRandomParam(): Parameters = {
    val captcha = pickRandom(config.captchaConfig)
    val level = pickRandom(captcha.allowedLevels)
    val media = pickRandom(captcha.allowedMedia)
    val inputType = pickRandom(captcha.allowedInputType)
    val size = pickRandom(captcha.allowedSizes)

    Parameters(level, media, inputType, size)
  }

  private def pickRandom[T](list: List[T]): T = {
    list(HelperFunctions.randomNumber(list.size))
  }

  private val ex = new ScheduledThreadPoolExecutor(1)

  def beginThread(delay: Int): Unit = {
    ex.scheduleWithFixedDelay(task, 1, delay, TimeUnit.SECONDS)
  }

  @volatile var shutdownInProgress = false

  def shutdown(): Unit = {
    println("  Shutting down background task...")
    shutdownInProgress = true
    ex.shutdown()
    println("    Finished Shutting background task")
    println("  Shutting down DB...")
    Statements.tlStmts.get.shutdown.execute()
    println("    Finished shutting down db")
  }

}
