import { BackgammonBoard } from './board'
import { BackgammonMoveOrigin } from './checkercontainer'
import { BackgammonCube } from './cube'
import { IntegerRange } from './generics'
import {
  BackgammonPlay,
  BackgammonPlayDoubled,
  BackgammonPlayMoving,
  BackgammonPlayRolled,
} from './play'
import {
  BackgammonPlayer,
  BackgammonPlayerActive,
  BackgammonPlayerDoubled,
  BackgammonPlayerInactive,
  BackgammonPlayerMoving,
  BackgammonPlayerRolled,
  BackgammonPlayerRolledForStart,
  BackgammonPlayerRolling,
  BackgammonPlayerWinner,
  BackgammonPlayers,
} from './player'

// --------------------------------------------------------------------------------------
// DESIGN NOTE: Game State Modeling - "playing"/"played" vs. "moving"/"moved"
//
// The current model uses "moving" and "moved" states, which are primarily driven by UI events
// (e.g., when a user clicks or drags a checker). However, in the rules of backgammon, a player's
// turn (a "play") consists of a sequence of moves (2 or 4, depending on the dice roll), and the
// turn is only complete when the player has finished all possible/legal moves and explicitly
// indicates they are done (e.g., by clicking a "Done" button).
//
// A more accurate and robust model would use "playing" and "played" states:
//   - "playing": The player is in the process of making their play (their turn), which may consist
//     of multiple moves. The player remains in this state until they indicate completion.
//   - "played": The player has finished their play (clicked "Done"), and the game can validate
//     the play and transition to the next state (e.g., next player's turn, or game end).
//
// This approach:
//   - Aligns the state machine with the actual rules and flow of backgammon, not just UI actions.
//   - Makes it easier to reason about game logic, validation, and undo/redo functionality.
//   - Separates UI-driven pseudo-states from rule-driven game states, leading to a cleaner design.
//
// For now, the code retains "moving" and "moved" for compatibility, but a future refactor should
// implement "playing" and "played" as described above.
// --------------------------------------------------------------------------------------

export type Latitude = 'north' | 'south'
export type Longitude = 'east' | 'west'
export type BackgammonColor = 'black' | 'white'
export type BackgammonMoveDirection = 'clockwise' | 'counterclockwise'
export type BackgammonPips = IntegerRange<1, 167>

export const MAX_PIP_COUNT = 167
export const CHECKERS_PER_PLAYER = 15

export type BackgammonGameStateKind =
  | 'rolling-for-start'
  | 'rolled-for-start'
  | 'rolling'
  | 'rolled'
  | 'doubling'
  | 'doubled'
  | 'moving'
  | 'moved'
  | 'completed'

interface BaseGame {
  id: string
  players: BackgammonPlayers
  board: BackgammonBoard
  cube: BackgammonCube
  winner?: BackgammonPlayer
  activeColor?: BackgammonColor
  activePlay?: BackgammonPlay
  activePlayer?: BackgammonPlayer
  inactivePlayer?: BackgammonPlayer
}

interface Game extends BaseGame {
  stateKind: BackgammonGameStateKind
}

export type BackgammonGameRollingForStart = Game & {
  stateKind: 'rolling-for-start'
}

export type BackgammonGameRolledForStart = Game & {
  stateKind: 'rolled-for-start'
  activeColor: BackgammonColor
  activePlayer: BackgammonPlayerRolledForStart
  inactivePlayer: BackgammonPlayerInactive
}

export type BackgammonGameRolling = Game & {
  stateKind: 'rolling'
  activeColor: BackgammonColor
  activePlayer: BackgammonPlayerRolling
  inactivePlayer: BackgammonPlayerInactive
}

// Changed activePlayer to BackgammonPlayerRolled
export type BackgammonGameRolled = Game & {
  stateKind: 'rolled'
  activeColor: BackgammonColor
  activePlayer: BackgammonPlayerRolled
  inactivePlayer: BackgammonPlayerInactive
  activePlay: BackgammonPlayRolled
}

export type BackgammonGameDoubling = Game & {
  stateKind: 'doubling'
  activeColor: BackgammonColor
  activePlay: BackgammonPlayDoubled
  activePlayer: BackgammonPlayerDoubled
  inactivePlayer: BackgammonPlayerInactive
}

export type BackgammonGameDoubled = Game & {
  stateKind: 'doubled'
  activeColor: BackgammonColor
  activePlay: BackgammonPlayDoubled
  activePlayer: BackgammonPlayerDoubled
  inactivePlayer: BackgammonPlayerInactive
}

export type BackgammonGameMoving = Game & {
  stateKind: 'moving'
  activeColor: BackgammonColor
  activePlay: BackgammonPlayMoving
  activePlayer: BackgammonPlayerMoving
  inactivePlayer: BackgammonPlayerInactive
}

export type BackgammonGameMoved = Game & {
  stateKind: 'moved'
  activeColor: BackgammonColor
  activePlay: BackgammonPlayMoving
  activePlayer: BackgammonPlayerMoving
  inactivePlayer: BackgammonPlayerInactive
}

export type BackgammonGameCompleted = Game & {
  stateKind: 'completed'
  winner: BackgammonPlayerWinner
}

export type BackgammonGame =
  | BackgammonGameRollingForStart
  | BackgammonGameRolledForStart
  | BackgammonGameRolling
  | BackgammonGameRolled
  | BackgammonGameDoubled
  | BackgammonGameMoving
  | BackgammonGameMoved
  | BackgammonGameCompleted

export interface GameProps {
  players: BackgammonPlayers
  board?: BackgammonBoard
  cube?: BackgammonCube
}

export interface GameClass {
  id: string
  stateKind: BackgammonGameStateKind
  players: BackgammonPlayers
  board: BackgammonBoard
  cube: BackgammonCube
  activeColor: BackgammonColor
  activePlay: BackgammonPlay
  activePlayer: BackgammonPlayerActive
  inactivePlayer: BackgammonPlayerInactive

  initialize: (
    players: BackgammonPlayers,
    id?: string,
    stateKind?: BackgammonGameStateKind,
    board?: BackgammonBoard,
    cube?: BackgammonCube,
    activePlay?: BackgammonPlay,
    activeColor?: BackgammonColor,
    activePlayer?: BackgammonPlayerActive,
    inactivePlayer?: BackgammonPlayerInactive,
    origin?: BackgammonMoveOrigin
  ) => BackgammonGame
  rollForStart: (
    game: BackgammonGameRollingForStart
  ) => BackgammonGameRolledForStart
  roll: (game: BackgammonGameRolledForStart) => BackgammonGameRolled
  /**
   * This is a pseudo state transition. The user transitions into a "moving" state when they
   * click on a checker (rather than the cube). But the instant they click the
   * checker they are in a moved state.
   */
  toMoving: (
    game: BackgammonGameRolled | BackgammonGameDoubled
  ) => BackgammonGameMoving
  /**
   * This is another pseudo state transition. Argument for this is weaker.
   */
  toDoubling: (game: BackgammonGameRolled) => BackgammonGameDoubling
  double: (game: BackgammonGameDoubling) => BackgammonGameDoubled
  move: (
    game: BackgammonGameMoving | BackgammonGameRolled,
    origin: BackgammonMoveOrigin
  ) => BackgammonGameMoved
  getActivePlayer: (game: BackgammonGame) => BackgammonPlayerActive
  getInactivePlayer: (game: BackgammonGame) => BackgammonPlayerInactive
  getPlayersForColor: (
    players: BackgammonPlayers,
    color: BackgammonColor
  ) => [BackgammonPlayerActive, BackgammonPlayerInactive]
  sanityCheckMovingGame: (game: BackgammonGame) => BackgammonGameMoving | false
}
