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

import java.util.UUID
import org.scalatest.{ Matchers, WordSpec }
import pl.edu.pw.mini.sg.game.graph.{ DeterministicGraphGameConfig, Edge, GraphConfig }


final class DiscountingGraphGameSpec extends WordSpec with Matchers {
  val graph = GraphConfig(5, Vector(
    Edge(0,4), Edge(4,0), Edge(4,1), Edge(1,4), Edge(2,4), Edge(4,2), Edge(3,4), Edge(4,3)
  ))
  val gameConfig = DiscountingGraphGameConfig(
    DeterministicGraphGameConfig(
      graph,
      List(1,2), 3,
      Vector.fill(5)(0.6),
      Vector.fill(5)(0.2),
      Vector(0.1, 0.2),
      Vector(0.8, 0.9),
      2, 3, UUID.nameUUIDFromBytes(Array(0))
    ),
    0, 0,
    UUID.nameUUIDFromBytes(Array(0))
  )

  "game without penalties" when {
    val game = DiscountingGraphGameFactory.create(gameConfig)

    "playing initial state"  should {
      "offer attacker moves 3,4" in {
        game.attackerState.possibleMoves should contain only (3, 4)
      }

      "offer defender moves 0,4" in {
        game.defenderState.possibleMoves should contain only(0,4)
      }

      "have timeStep 0" in {
        game.defenderState.timeStep should equal(0)
        game.attackerState.timeStep should equal(0)
      }

      "playing moves (0,3)" should {
        val gg = game.makeMove(0, 3)

        "offer defender moves 0,4" in {
          gg.defenderState.possibleMoves should contain only(0,4)
        }

        "offer attacker moves 3" in {
          gg.attackerState.possibleMoves should contain only (3)
        }

        "have timeStep 0" in {
          gg.defenderState.timeStep should equal(0)
          gg.attackerState.timeStep should equal(0)
        }
      }

      "playing moves (0,4), (0,4)" should {
        val gg = game.makeMove(0, 4).makeMove(0, 4)

        "offer defender moves 0,4" in {
          gg.defenderState.possibleMoves should contain only(0,4)
        }

        "offer attacker moves 0,1,2,3,4" in {
          gg.attackerState.possibleMoves should contain only (0,1,2,3,4)
        }

        "have timeStep 1" in {
          gg.defenderState.timeStep should equal(1)
          gg.attackerState.timeStep should equal(1)
        }
      }

      "playing moves (0,4) (0,4) (3,1) (3,1)" should {
        val gg = game.makeMove(0, 4).makeMove(0, 4).makeMove(3,1).makeMove(3,1)
        "not offer any moves" in {
          gg.defenderState.possibleMoves shouldBe empty
          gg.attackerState.possibleMoves shouldBe empty
        }

        "give defender payoff 0.1" in {
          gg.defenderPayoff should equal(0.1)
        }

        "give attacker payoff 0.8" in {
          gg.attackerPayoff should equal (0.8)
        }
      }
    }
  }

  "game with single defender" when {
    val game = DiscountingGraphGameFactory.create(DiscountingGraphGameConfig(
      gameConfig.graphConfig.copy(defenderUnitCount = 1), 0, 0, UUID.nameUUIDFromBytes(Array(0))
    ))

    "playing moves (0,4)" should {
      val gg = game.makeMove(0,4)
      "have time step 1" in {
        gg.defenderState.timeStep should equal(1)
        gg.attackerState.timeStep should equal(1)
      }

      "offer defender moves 0,4" in {
        gg.defenderState.possibleMoves should contain only (0,4)
      }

      "offer defender moves 0,1,2,3,4" in {
        gg.attackerState.possibleMoves should contain only (0,1,2,3,4)
      }
    }
  }

  "game with attacker penalnty 0.1" when {
    val game = DiscountingGraphGameFactory.create(gameConfig.copy(attackerRoundLoss = 0.05))

    "playing moves (0,4) (0,4) (0,1) (0,1)" should {
      val gg = game.makeMove(0,3).makeMove(0,4).makeMove(0,1).makeMove(0,1)

      "not offer any moves" in {
        gg.defenderState.possibleMoves shouldBe empty
        gg.attackerState.possibleMoves shouldBe empty
      }

      "give defender payoff 0.1" in {
        gg.defenderPayoff should equal(0.1)
      }

      "give attacker payoff 0.75" in {
        gg.attackerPayoff should equal (0.75)
      }
    }

    "playing moves (0,3) (4,3) (0,4) (1,4)" should {
      val gg = game.makeMove(0,3).makeMove(4,3).makeMove(0,4).makeMove(1,4)
        "allow defender moves 0,4" in {
           gg.defenderState.possibleMoves should contain only(0,4)
        }

       "have timeStep 2" in {
          gg.defenderState.timeStep should equal(2)
          gg.attackerState.timeStep should equal(2)
       }
     }

    "playing moves (0,3) (4,3) (0,4) (1,4) (0,1)" should {
      val gg = game.makeMove(0,3).makeMove(4,3).makeMove(0,4).makeMove(1,4).makeMove(0,1)
        "allow defender moves 1,4" in {
           gg.defenderState.possibleMoves should contain only(4,1)
        }

       "have timeStep 2" in {
          gg.defenderState.timeStep should equal(2)
          gg.attackerState.timeStep should equal(2)
       }
     }


    "playing moves (0,3) (4,3) (0,4) (1,4) (0,1) (1,1)" should {
      val gg = game.makeMove(0,3).makeMove(4,3).makeMove(0,4).makeMove(1,4).makeMove(0,1).makeMove(1,1)

      "not offer any moves" in {
        gg.defenderState.possibleMoves shouldBe empty
        gg.attackerState.possibleMoves shouldBe empty
      }

      "give defender payoff 0.6" in {
        gg.defenderPayoff should equal(0.6)
      }

      "give attacker payoff 0.1" in {
        gg.attackerPayoff should equal (0.1)
      }
    }
  }
}
