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

import canes.game.{ Depot, MovingTargetsGame, Target }
import java.util.UUID
import org.scalatest._
import pl.edu.pw.mini.sg.movingtargets.{ MovingTargetsGameConfig }
import collection.JavaConverters._

class CoordAttackerStateSpec extends WordSpec with Matchers {
  "CoordAttackerState for two defender game" should {

    val game = MovingTargetsGameConfig(MovingTargetsGame(
      UUID.fromString("123e4567-e89b-12d3-a456-426655440000"),
      List(Depot(1, 5, 6), Depot(2, 6, 7)),
        List(
          Target(2, 1, 2, List(3,4,5), 1,-1,-1,1)
        ),
      1, 2, 2, List(1,2), 1, 100, 2, 0), 3)

    val state = CoordAttackerState.initialState(game)

    "Allow attack and wait in first move" in {
      state.getPossibleMoves.asScala should contain only (WaitDecision, AttackDecision(2))
    }

    "Allow only dummy move in second move" in {
      state.advance(WaitDecision).getPossibleMoves.asScala should contain only (DummyMove)
    }

    "Allow only dummy move in third move" in {
      state.advance(WaitDecision).advance(DummyMove).getPossibleMoves.asScala should contain only (DummyMove)
    }

    "Allow only dummy move in the fourth move" in {
      state.advance(WaitDecision).advance(DummyMove).advance(DummyMove).getPossibleMoves.asScala should contain only (DummyMove)
    }

    "Allow attack and wait in fifth move" in {
      state.advance(WaitDecision).advance(DummyMove).advance(DummyMove).advance(DummyMove).getPossibleMoves.asScala should contain only (WaitDecision, AttackDecision(2))
    }

    "Allow only wait in fifth move if attacked first" in {
      state.advance(AttackDecision(2)).advance(DummyMove).advance(DummyMove).advance(DummyMove).getPossibleMoves.asScala should contain only (WaitDecision)
    }

    "throw illegal argument exception when playing dummy move first" in {
      an[IllegalArgumentException] shouldBe thrownBy(state.advance(DummyMove))
    }

    "throw an illegal argument exception when playing wait move second" in {
      an[IllegalArgumentException] shouldBe thrownBy(state.advance(WaitDecision).advance(WaitDecision))
    }

    "throw an illegal argument exception when attacking nonexistent target" in {
      an[IllegalArgumentException] shouldBe thrownBy(state.advance(AttackDecision(1)))
    }
  }

  "CoordAttackerState for one defender game" should {

    val game = MovingTargetsGameConfig(MovingTargetsGame(UUID.fromString("123e4567-e89b-12d3-a456-426655440000"),
      List(Depot(1, 5, 6), Depot(2, 6, 7)),
        List(
          Target(2, 1, 2, List(3,4,5), 1,-1,-1,1)
        ),
      1, 1, 2, List(2), 1, 100, 2, 0), 3)

    val state = CoordAttackerState.initialState(game)

    "Allow attack and wait in first move" in {
      state.getPossibleMoves.asScala should contain only (WaitDecision, AttackDecision(2))
    }

    "Allow only dummy move in second move" in {
      state.advance(WaitDecision).getPossibleMoves.asScala should contain only (DummyMove)
    }
    "Allow attack and wait in third move" in {
      state.advance(WaitDecision).advance(DummyMove).getPossibleMoves.asScala should contain only (WaitDecision, AttackDecision(2))
    }

    "Allow only wait in third move if attacked first" in {
      state.advance(AttackDecision(2)).advance(DummyMove).getPossibleMoves.asScala should contain only (WaitDecision)
    }

    "throw illegal argument exception when playing dummy move first" in {
      an[IllegalArgumentException] shouldBe thrownBy(state.advance(DummyMove))
    }

    "throw an illegal argument exception when playing wait move second" in {
      an[IllegalArgumentException] shouldBe thrownBy(state.advance(WaitDecision).advance(WaitDecision))
    }

    "throw an illegal argument exception when attacking nonexistent target" in {
      an[IllegalArgumentException] shouldBe thrownBy(state.advance(AttackDecision(1)))
    }
  }
}
