package de.nowchess.chess.engine

import de.nowchess.api.board.Color
import de.nowchess.api.game.GameContext
import de.nowchess.bot.{BotDifficulty, ClassicalBot, BotController}
import de.nowchess.chess.observer.*
import de.nowchess.rules.sets.DefaultRules
import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers
import scala.concurrent.duration.*
import scala.concurrent.Await

class GameEngineWithBotTest extends AnyFunSuite with Matchers:

  test("GameEngine can play against a ClassicalBot"):
    val engine = GameEngine(GameContext.initial, DefaultRules)
    val bot = ClassicalBot(BotDifficulty.Easy)

    // Set White (human) vs Black (bot)
    engine.setOpponentBot(bot, Color.Black)

    // Collect events
    var moveCount = 0
    var checkmateDetected = false
    var gameEnded = false

    val observer = new Observer:
      def onGameEvent(event: GameEvent): Unit =
        event match
          case _: MoveExecutedEvent =>
            moveCount += 1
          case _: CheckmateEvent =>
            checkmateDetected = true
            gameEnded = true
          case _: StalemateEvent =>
            gameEnded = true
          case _ => ()

    engine.subscribe(observer)

    // Play a few moves: e2e4, then let the bot respond
    engine.processUserInput("e2e4")

    // Wait a bit for the bot to respond asynchronously
    Thread.sleep(5000)

    // White should have moved, then Black (bot) should have responded
    moveCount should be >= 2

    engine.clearOpponentBot()

  test("BotController can list and retrieve bots"):
    val bots = BotController.listBots
    bots should contain("easy")
    bots should contain("medium")
    bots should contain("hard")
    bots should contain("expert")

    BotController.getBot("easy") should not be None
    BotController.getBot("medium") should not be None
    BotController.getBot("hard") should not be None
    BotController.getBot("expert") should not be None
    BotController.getBot("unknown") should be(None)

  test("GameEngine handles bot with different difficulty"):
    val engine = GameEngine(GameContext.initial, DefaultRules)
    val hardBot = BotController.getBot("hard").get

    engine.setOpponentBot(hardBot, Color.Black)
    engine.turn should equal(Color.White)

    var movesMade = 0
    val observer = new Observer:
      def onGameEvent(event: GameEvent): Unit =
        event match
          case _: MoveExecutedEvent => movesMade += 1
          case _ => ()

    engine.subscribe(observer)

    // White moves
    engine.processUserInput("d2d4")
    Thread.sleep(500)  // Wait for bot response

    // At least white moved, possibly black also responded
    movesMade should be >= 1

    engine.clearOpponentBot()

  test("GameEngine plays valid bot moves"):
    val engine = GameEngine(GameContext.initial, DefaultRules)
    val bot = ClassicalBot(BotDifficulty.Easy)

    engine.setOpponentBot(bot, Color.Black)

    var moveCount = 0
    val observer = new Observer:
      def onGameEvent(event: GameEvent): Unit =
        event match
          case _: MoveExecutedEvent => moveCount += 1
          case _ => ()

    engine.subscribe(observer)

    // Play a normal move
    engine.processUserInput("e2e4")
    Thread.sleep(1000)

    // The game should have progressed with at least one move
    moveCount should be >= 1
    // Game should not be ended (checkmate/stalemate)
    engine.context.moves.nonEmpty should be(true)

    engine.clearOpponentBot()
