package de.nowchess.backcore.resource

import io.quarkus.test.junit.QuarkusTest
import io.restassured.RestAssured
import org.hamcrest.Matchers.{containsString, empty, equalTo, hasItem, hasItems, not, notNullValue}
import org.junit.jupiter.api.Test

@QuarkusTest
class MoveResourceTest:

  private def createGame(): String =
    RestAssured
      .`given`()
      .contentType("application/json")
      .body("{}")
      .when()
      .post("/api/board/game")
      .`then`()
      .statusCode(201)
      .extract()
      .path[String]("gameId")

  @Test
  def makeMoveReturns200WithUpdatedFen(): Unit =
    val gameId = createGame()
    RestAssured
      .`given`()
      .when()
      .post(s"/api/board/game/$gameId/move/e2e4")
      .`then`()
      .statusCode(200)
      .body("fen", containsString("4P3")) // e4 pawn present in FEN
      .body("turn", equalTo("black"))
      .body("moves", hasItem("e2e4"))

  @Test
  def makeMoveOnUnknownGameReturns404(): Unit =
    RestAssured
      .`given`()
      .when()
      .post("/api/board/game/XXXXXXXX/move/e2e4")
      .`then`()
      .statusCode(404)

  @Test
  def illegalMoveReturns400(): Unit =
    val gameId = createGame()
    RestAssured
      .`given`()
      .when()
      .post(s"/api/board/game/$gameId/move/e2e5") // illegal — pawns can't jump 3 squares
      .`then`()
      .statusCode(400)

  @Test
  def getLegalMovesReturnsNonEmptyList(): Unit =
    val gameId = createGame()
    RestAssured
      .`given`()
      .when()
      .get(s"/api/board/game/$gameId/moves")
      .`then`()
      .statusCode(200)
      .body("moves", not(empty()))

  @Test
  def getLegalMovesFilteredBySquareReturnsCorrectMoves(): Unit =
    val gameId = createGame()
    RestAssured
      .`given`()
      .when()
      .get(s"/api/board/game/$gameId/moves?square=e2")
      .`then`()
      .statusCode(200)
      .body("moves.uci", hasItems("e2e3", "e2e4"))

  @Test
  def getLegalMovesOnUnknownGameReturns404(): Unit =
    RestAssured
      .`given`()
      .when()
      .get("/api/board/game/XXXXXXXX/moves")
      .`then`()
      .statusCode(404)

  @Test
  def getLegalMovesIncludesCaptureType(): Unit =
    val gameId = RestAssured
      .`given`()
      .contentType("application/json")
      .body("""{"fen":"rnbqkbnr/ppp1pppp/8/3p4/4P3/8/PPPP1PPP/RNBQKBNR w KQkq d6 0 2"}""")
      .when()
      .post("/api/board/game/import/fen")
      .`then`()
      .statusCode(201)
      .extract()
      .path[String]("gameId")
    RestAssured
      .`given`()
      .when()
      .get(s"/api/board/game/$gameId/moves?square=e4")
      .`then`()
      .statusCode(200)
      .body("moves.moveType", hasItem("capture"))

  @Test
  def getLegalMovesIncludesCastlingTypes(): Unit =
    val gameId = RestAssured
      .`given`()
      .contentType("application/json")
      .body("""{"fen":"4k3/8/8/8/8/8/8/R3K2R w KQ - 0 1"}""")
      .when()
      .post("/api/board/game/import/fen")
      .`then`()
      .statusCode(201)
      .extract()
      .path[String]("gameId")
    RestAssured
      .`given`()
      .when()
      .get(s"/api/board/game/$gameId/moves?square=e1")
      .`then`()
      .statusCode(200)
      .body("moves.moveType", hasItems("castleKingside", "castleQueenside"))

  @Test
  def getLegalMovesIncludesEnPassantType(): Unit =
    val gameId = RestAssured
      .`given`()
      .contentType("application/json")
      .body("""{"fen":"rnbqkbnr/ppp1p1pp/8/3pPp2/8/8/PPPP1PPP/RNBQKBNR w KQkq f6 0 3"}""")
      .when()
      .post("/api/board/game/import/fen")
      .`then`()
      .statusCode(201)
      .extract()
      .path[String]("gameId")
    RestAssured
      .`given`()
      .when()
      .get(s"/api/board/game/$gameId/moves?square=e5")
      .`then`()
      .statusCode(200)
      .body("moves.moveType", hasItem("enPassant"))

  @Test
  def getLegalMovesIncludesAllPromotionTypes(): Unit =
    val gameId = RestAssured
      .`given`()
      .contentType("application/json")
      .body("""{"fen":"8/4P3/8/8/8/8/8/4K2k w - - 0 1"}""")
      .when()
      .post("/api/board/game/import/fen")
      .`then`()
      .statusCode(201)
      .extract()
      .path[String]("gameId")
    RestAssured
      .`given`()
      .when()
      .get(s"/api/board/game/$gameId/moves?square=e7")
      .`then`()
      .statusCode(200)
      .body("moves.promotion", hasItems("rook", "bishop", "knight"))
