package de.nowchess.rules

import de.nowchess.api.game.GameContext
import de.nowchess.api.board.Square
import de.nowchess.api.move.Move

/** Extension point for chess rule variants (standard, Chess960, etc.). All rule queries are stateless: given a
  * GameContext, return the answer.
  */
trait RuleSet:
  /** All pseudo-legal moves for the piece on `square` (ignores check). */
  def candidateMoves(context: GameContext)(square: Square): List[Move]

  /** Legal moves for `square`: candidates that don't leave own king in check. */
  def legalMoves(context: GameContext)(square: Square): List[Move]

  /** All legal moves for the side to move. */
  def allLegalMoves(context: GameContext): List[Move]

  /** True if the side to move's king is in check. */
  def isCheck(context: GameContext): Boolean

  /** True if the side to move is in check and has no legal moves. */
  def isCheckmate(context: GameContext): Boolean

  /** True if the side to move is not in check and has no legal moves. */
  def isStalemate(context: GameContext): Boolean

  /** True if neither side has enough material to checkmate. */
  def isInsufficientMaterial(context: GameContext): Boolean

  /** True if halfMoveClock >= 100 (50-move rule). */
  def isFiftyMoveRule(context: GameContext): Boolean

  /** True if the same position has occurred 3 times (including current position). */
  def isThreefoldRepetition(context: GameContext): Boolean

  /** Apply a legal move to produce the next game context. Handles all special move types: castling, en passant,
    * promotion. Updates castling rights, en passant square, half-move clock, turn, and move history.
    */
  def applyMove(context: GameContext)(move: Move): GameContext
