package pl.edu.pw.mini.sg.movingtargets.coord

import canes.game.{ Depot, MovingTargetsGame, Target }
import java.util.UUID
import org.scalatest.{WordSpec, Matchers }
import pl.edu.pw.mini.jk.sg.game.immutable.Payoffs
import pl.edu.pw.mini.sg.movingtargets.{ AttackStart, MovingTargetsGameConfig }

class CoordImmutableGameSpec extends WordSpec with Matchers {
  "CoordImmutableGame" when {
    "playing game with single round attack" should {
      val gameConfig = MovingTargetsGameConfig(MovingTargetsGame(UUID.fromString("123e4567-e89b-12d3-a456-426655440000"),
        List(Depot(1, 5, 5), Depot(2,20,20)),
        List(Target(1, 1, 2, List(2,33,50), 10, -5, -8, 4)),
        0.5, 2, 2, List(1,1), 1, 100, 1, 0), 1)

      val game = CoordImmutableGame.initialState(gameConfig)

      val imm1 = game.makeMoves(XMove(2), AttackDecision(1))
      val imm2 = imm1._2.makeMoves(YMove(0), DummyMove)
      val imm3 = imm2._2.makeMoves(XMove(2), DummyMove)
      val fin = imm3._2.makeMoves(YMove(0), DummyMove)

      val prot3 = imm2._2.makeMoves(XMove(0), DummyMove)
      val finp = prot3._2.makeMoves(YMove(0), DummyMove)


      "not give rewards in partial moves" in {
        imm1._1 shouldEqual(Payoffs(0,0,0,0))
        imm2._1 shouldEqual(Payoffs(0,0,0,0))
        imm3._1 shouldEqual(Payoffs(0,0,0,0))
      }

      "have attack started in partial moves" in {
        imm1._2.attackStarted shouldEqual(Some(AttackStart(1, 1)))
        imm2._2.attackStarted shouldEqual(Some(AttackStart(1, 1)))
        imm3._2.attackStarted shouldEqual(Some(AttackStart(1, 1)))
      }

      "give attacker reward when round finished" in {
        fin._1.shouldEqual(Payoffs(-8, 10, 1, 0))
      }

      "give defender reward when protecting" in {
        finp._1.shouldEqual(Payoffs(4,-5,0,1))
      }

      "clear attack started after succeed" in {
        fin._2.attackStarted shouldEqual(None)
      }

      "clear attack started after failed" in {
        finp._2.attackStarted shouldEqual(None)
      }
    }

    "playing game with three round attack" should {
      val gameConfig = MovingTargetsGameConfig(MovingTargetsGame(UUID.fromString("123e4567-e89b-12d3-a456-426655440000"),
        List(Depot(1, 5, 5), Depot(2,20,20)),
        List(Target(1, 1, 2, List(2,33,50), 10, -5, -8, 4)),
        0.5, 2, 2, List(1,1), 1, 100, 1, 2), 1)

      val game = CoordImmutableGame.initialState(gameConfig)

      val noProtDefenderMoves = List(XMove(2), YMove(0), XMove(2), YMove(0))
      val protDefenderMoves = List(XMove(0), YMove(0), XMove(0), YMove(0))
      val attackMoves = List(AttackDecision(1), DummyMove, DummyMove, DummyMove)
      val waitMoves = List(WaitDecision, DummyMove, DummyMove, DummyMove)


      val firstNoProt = noProtDefenderMoves.zip(attackMoves).foldLeft((Payoffs(0,0,0,0), game))
      { case (game, (dm, am)) => game._2.makeMoves(dm, am) }

      val secondNoProt = noProtDefenderMoves.zip(waitMoves).foldLeft(firstNoProt)
      { case (game, (dm, am)) => game._2.makeMoves(dm, am) }

      val thirdNoProt = noProtDefenderMoves.zip(waitMoves).foldLeft(secondNoProt) { case (game, (dm, am)) => game._2.makeMoves(dm, am) }

      "not give payoffs after first two unprotected rounds" in {
        firstNoProt._1 shouldEqual(Payoffs(0,0,0,0))
        secondNoProt._1 shouldEqual(Payoffs(0,0,0,0))
      }

      "give attacker reward in third unprotected round" in {
        thirdNoProt._1 shouldEqual(Payoffs(-8, 10, 1, 0))
      }

      val firstProt = protDefenderMoves.zip(attackMoves).foldLeft((Payoffs(0,0,0,0), game)) {
        case (game, (dm, am)) => game._2.makeMoves(dm, am)
      }
      val secondProt = protDefenderMoves.zip(waitMoves).foldLeft(firstNoProt) {
        case (game, (dm, am)) => game._2.makeMoves(dm, am)
      }
      val thirdProt = protDefenderMoves.zip(waitMoves).foldLeft(secondNoProt) {
        case (game, (dm, am)) => game._2.makeMoves(dm, am)
      }
      "give defender reward when protected in third round" in {
        thirdProt._1.shouldEqual(Payoffs(4,-5,0,1))
      }

      "give defender reward when protected in second round" in {
        secondProt._1.shouldEqual(Payoffs(4,-5,0,1))
      }

      "give defender reward when protected in first round" in {
        firstProt._1.shouldEqual(Payoffs(4,-5,0,1))
      }

      "clear attackStarted after success" in {
        thirdNoProt._2.attackStarted shouldEqual(None)
      }

      "clear attackStarted after failure" in {
        thirdProt._2.attackStarted.shouldEqual(None)
        secondProt._2.attackStarted shouldEqual(None)
        firstProt._2.attackStarted shouldEqual(None)
      }

    }

  }
}
