package de.nowchess.backcore.game

import de.nowchess.api.board.Color
import de.nowchess.api.game.GameContext
import de.nowchess.api.player.{PlayerId, PlayerInfo}
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.Test

import java.io.{ByteArrayOutputStream, ObjectOutputStream}

/** Exercises Scala-generated synthetic methods on domain case classes and serializes singleton
  * objects (Scala objects implement Serializable; writeReplace is called on serialization).
  */
class GameDomainCoverageTest:

  private val white = PlayerInfo(PlayerId("white"), "White")
  private val black = PlayerInfo(PlayerId("black"), "Black")

  private def freshSnap(canUndo: Boolean = false, canRedo: Boolean = false): GameSnapshot =
    GameSnapshot(
      gameId = "g1",
      white = white,
      black = black,
      context = GameContext.initial,
      canUndo = canUndo,
      canRedo = canRedo,
    )

  @Test
  def gameResultResignSynthetics(): Unit =
    val a = GameResult.Resign(Color.White)
    val b = GameResult.Resign(Color.White)
    val c = GameResult.Resign(Color.Black)
    assertEquals(a, b)
    assertNotEquals(a, c)
    assertFalse(a.equals(null))
    assertFalse(a.equals("other"))
    assertEquals(a.hashCode, b.hashCode)
    assertTrue(a.toString.contains("White"))
    assertTrue(a.canEqual(b))
    assertEquals(Color.White, a.productElement(0))
    assertEquals("winner", a.productElementName(0))
    assertEquals(a, a.copy())
    assertEquals(GameResult.Resign(Color.Black), a.copy(winner = Color.Black))

  @Test
  def gameSnapshotSynthetics(): Unit =
    val a = freshSnap()
    val b = freshSnap()
    val c = freshSnap(canUndo = true)
    assertEquals(a, b)
    assertNotEquals(a, c)
    assertFalse(a.equals(null))
    assertFalse(a.equals("other"))
    assertEquals(a.hashCode, b.hashCode)
    assertTrue(a.canEqual(b))
    assertEquals("g1", a.productElement(0))
    assertEquals(white, a.productElement(1))
    assertEquals(black, a.productElement(2))
    assertEquals(GameContext.initial, a.productElement(3))
    assertEquals(None, a.productElement(4))
    assertEquals(None, a.productElement(5))
    assertEquals(false, a.productElement(6))
    assertEquals(false, a.productElement(7))
    assertEquals("gameId", a.productElementName(0))
    assertEquals("white", a.productElementName(1))
    assertEquals("black", a.productElementName(2))
    assertEquals("context", a.productElementName(3))
    assertEquals("drawOfferedBy", a.productElementName(4))
    assertEquals("externalResult", a.productElementName(5))
    assertEquals("canUndo", a.productElementName(6))
    assertEquals("canRedo", a.productElementName(7))
    assertEquals(a, a.copy())
    assertEquals(freshSnap(canUndo = true), a.copy(canUndo = true))
    assertEquals(freshSnap(canRedo = true), a.copy(canRedo = true))

  @Test
  def gameMapperSingletonIsSerializable(): Unit =
    val bos = new ByteArrayOutputStream()
    val oos = new ObjectOutputStream(bos)
    oos.writeObject(GameMapper)
    oos.close()
    assertTrue(bos.size() > 0)

  @Test
  def gameEngineHolderSingletonIsSerializable(): Unit =
    val bos = new ByteArrayOutputStream()
    val oos = new ObjectOutputStream(bos)
    oos.writeObject(GameEngineHolder)
    oos.close()
    assertTrue(bos.size() > 0)
