package pl.edu.pw.mini.sg.game.graph.sud

import pl.edu.pw.mini.sg.rng.RandomGenerator
import pl.edu.pw.mini.sg.game.deterministic.AdvanceablePlayerVisibleState
import pl.edu.pw.mini.sg.game.graph.DeterministicGraphGameConfig
import pl.edu.pw.mini.sg.util.CachedHashPair
import scala.runtime.ScalaRunTime


final class SingleUnitAttackerState(
  val gameConfig: DeterministicGraphGameConfig,
  val attackerPosition: Int,
  val timeStep: Int,
  val complementaryDefender: Int
) extends AdvanceablePlayerVisibleState[Int, SingleUnitAttackerState] with Product3[Int, Int, Int] {

  override def toString = s"SUAS(${attackerPosition}, ${timeStep}, ${complementaryDefender})"

  override lazy val hashCode : Int = ScalaRunTime._hashCode(this)
  override def equals(other: Any) : Boolean = other match {
    case suas: SingleUnitAttackerState => attackerPosition == suas.attackerPosition && timeStep == suas.timeStep && complementaryDefender == suas.complementaryDefender
    case _ => false
  }

  override def canEqual(other: Any) : Boolean = other match {
    case _ : SingleUnitAttackerState => true
    case _ => false
  }


  override val _1 = attackerPosition
  override val _2 = timeStep
  override val _3 = complementaryDefender

  def continuation(move: Int) : SingleUnitAttackerState = {
    require(timeStep < gameConfig.rounds)
    require(possibleMoves.contains(move))

    gameConfig.attackerCache.get(CachedHashPair(move, this), (pair: CachedHashPair[Int, SingleUnitAttackerState]) => {
      if(complementaryDefender > 0) {
        require(move == -1)
        if(complementaryDefender == gameConfig.defenderUnitCount -1)
          new SingleUnitAttackerState(gameConfig, timeStep = timeStep + 1, complementaryDefender = 0, attackerPosition = attackerPosition)
        else
          new SingleUnitAttackerState(gameConfig, timeStep= timeStep, complementaryDefender = complementaryDefender + 1, attackerPosition = attackerPosition)
      } else {
        require(possibleMoves.contains(move))
        if(complementaryDefender == gameConfig.defenderUnitCount -1)
          new SingleUnitAttackerState(timeStep = timeStep + 1, complementaryDefender = 0, attackerPosition = move, gameConfig = gameConfig)
        else
          new SingleUnitAttackerState(complementaryDefender = complementaryDefender + 1, attackerPosition = move, gameConfig = gameConfig, timeStep = timeStep)
      }
    })
  }

  override def possibleContinuations(move: Int): List[SingleUnitAttackerState] = List(continuation(move))

  override def sampleContinuations(move: Int
  )(implicit rng: RandomGenerator): SingleUnitAttackerState = continuation(move)

  override def  possibleMoves: List[Int] =
    if(timeStep >= gameConfig.rounds)
      Nil
    else if(complementaryDefender > 0)
      List(-1)
    else
      gameConfig.possibleMovesFromVertex(attackerPosition)

}
