/**
 * WebSocket Event Types
 *
 * TypeScript definitions for all Socket.io events between client and server.
 * Ensures type safety for real-time communication.
 *
 * Backend Reference: app/websocket/handlers.py
 */

import type {
  GameState,
  PlayResult,
  DecisionPrompt,
  RollData,
  DefensiveDecision,
  OffensiveDecision,
  ManualOutcomeSubmission,
} from './game'

import type {
  SubstitutionRequest,
  SubstitutionResult,
  SubstitutionError,
  LineupDataResponse,
} from './player'

/**
 * WebSocket connection auth
 */
export interface SocketAuth {
  token: string
}

/**
 * Client → Server Events (what client can emit)
 */
export interface ClientToServerEvents {
  // Connection management
  join_game: (data: JoinGameRequest) => void
  leave_game: (data: LeaveGameRequest) => void
  heartbeat: () => void

  // Strategic decisions
  submit_defensive_decision: (data: DefensiveDecisionRequest) => void
  submit_offensive_decision: (data: OffensiveDecisionRequest) => void

  // Manual outcome workflow
  roll_dice: (data: RollDiceRequest) => void
  submit_manual_outcome: (data: SubmitManualOutcomeRequest) => void

  // Substitutions
  request_pinch_hitter: (data: PinchHitterRequest) => void
  request_defensive_replacement: (data: DefensiveReplacementRequest) => void
  request_pitching_change: (data: PitchingChangeRequest) => void

  // Data requests
  get_lineup: (data: GetLineupRequest) => void
  get_box_score: (data: GetBoxScoreRequest) => void
  request_game_state: (data: RequestGameStateRequest) => void
}

/**
 * Server → Client Events (what client can receive)
 */
export interface ServerToClientEvents {
  // Connection events
  connected: (data: ConnectedEvent) => void
  game_joined: (data: GameJoinedEvent) => void
  user_connected: (data: UserConnectedEvent) => void
  user_disconnected: (data: UserDisconnectedEvent) => void
  heartbeat_ack: () => void

  // Decision events
  defensive_decision_submitted: (data: DefensiveDecisionSubmittedEvent) => void
  offensive_decision_submitted: (data: OffensiveDecisionSubmittedEvent) => void
  decision_required: (data: DecisionPrompt) => void

  // Game state events
  game_state: (data: GameState) => void
  game_state_update: (data: GameState) => void
  game_state_sync: (data: GameStateSyncEvent) => void
  play_completed: (data: PlayResult) => void
  inning_change: (data: InningChangeEvent) => void
  game_ended: (data: GameEndedEvent) => void

  // Manual workflow events
  dice_rolled: (data: DiceRolledEvent) => void
  outcome_accepted: (data: OutcomeAcceptedEvent) => void

  // Substitution events
  player_substituted: (data: SubstitutionResult) => void
  substitution_confirmed: (data: SubstitutionConfirmedEvent) => void

  // Data responses
  lineup_data: (data: LineupDataResponse) => void
  box_score_data: (data: BoxScoreDataEvent) => void

  // Error events
  error: (data: ErrorEvent) => void
  outcome_rejected: (data: OutcomeRejectedEvent) => void
  substitution_error: (data: SubstitutionError) => void
  invalid_action: (data: InvalidActionEvent) => void
  connection_error: (data: ConnectionErrorEvent) => void
}

// ============================================================================
// Client → Server Request Types
// ============================================================================

export interface JoinGameRequest {
  game_id: string
  role: 'player' | 'spectator'
}

export interface LeaveGameRequest {
  game_id: string
}

export interface DefensiveDecisionRequest {
  game_id: string
  infield_depth: DefensiveDecision['infield_depth']
  outfield_depth: DefensiveDecision['outfield_depth']
  hold_runners: number[]
}

export interface OffensiveDecisionRequest {
  game_id: string
  action: OffensiveDecision['action']
  steal_attempts: number[]
}

export interface RollDiceRequest {
  game_id: string
}

export interface SubmitManualOutcomeRequest {
  game_id: string
  outcome: string
  hit_location?: string
}

export interface PinchHitterRequest {
  game_id: string
  player_out_lineup_id: number
  player_in_card_id: number
  team_id: number
}

export interface DefensiveReplacementRequest {
  game_id: string
  player_out_lineup_id: number
  player_in_card_id: number
  new_position: string
  team_id: number
}

export interface PitchingChangeRequest {
  game_id: string
  player_out_lineup_id: number
  player_in_card_id: number
  team_id: number
}

export interface GetLineupRequest {
  game_id: string
  team_id: number
}

export interface GetBoxScoreRequest {
  game_id: string
}

export interface RequestGameStateRequest {
  game_id: string
}

// ============================================================================
// Server → Client Event Types
// ============================================================================

export interface ConnectedEvent {
  user_id: string
}

export interface GameJoinedEvent {
  game_id: string
  role: 'player' | 'spectator'
}

export interface UserConnectedEvent {
  user_id: string
  game_id: string
}

export interface UserDisconnectedEvent {
  user_id: string
  game_id: string
}

export interface DefensiveDecisionSubmittedEvent {
  game_id: string
  decision: DefensiveDecision
  pending_decision: 'offensive' | 'resolution' | null
}

export interface OffensiveDecisionSubmittedEvent {
  game_id: string
  decision: OffensiveDecision
  pending_decision: 'resolution' | null
}

export interface DiceRolledEvent {
  game_id: string
  roll_id: string
  d6_one: number
  d6_two_total: number
  chaos_d20: number
  resolution_d20: number
  check_wild_pitch: boolean
  check_passed_ball: boolean
  timestamp: string
  message: string
}

export interface OutcomeAcceptedEvent {
  outcome: string
  hit_location?: string
}

export interface InningChangeEvent {
  inning: number
  half: 'top' | 'bottom'
}

export interface GameEndedEvent {
  game_id: string
  winner_team_id: number
  final_score: {
    home: number
    away: number
  }
  completed_at: string
}

export interface SubstitutionConfirmedEvent {
  type: string
  new_lineup_id: number
  message: string
}

export interface BoxScoreDataEvent {
  game_id: string
  box_score: {
    game_stats: {
      home_runs: number
      away_runs: number
      home_hits: number
      away_hits: number
      home_errors: number
      away_errors: number
      linescore_home: number[]
      linescore_away: number[]
    }
    batting_stats: BattingStatLine[]
    pitching_stats: PitchingStatLine[]
  }
}

export interface BattingStatLine {
  lineup_id: number
  player_card_id: number
  pa: number
  ab: number
  run: number
  hit: number
  rbi: number
  double: number
  triple: number
  hr: number
  bb: number
  so: number
  hbp: number
  sac: number
  sb: number
  cs: number
  gidp: number
}

export interface PitchingStatLine {
  lineup_id: number
  player_card_id: number
  batters_faced: number
  ip: number
  hit_allowed: number
  run_allowed: number
  erun: number
  bb: number
  so: number
  hbp: number
  hr_allowed: number
  wp: number
}

export interface GameStateSyncEvent {
  state: GameState
  recent_plays: PlayResult[]
  timestamp: string
}

export interface ErrorEvent {
  message: string
  code?: string
  field?: string
  hint?: string
}

export interface OutcomeRejectedEvent {
  message: string
  field: string
  errors?: Array<{
    loc: string[]
    msg: string
    type: string
  }>
}

export interface InvalidActionEvent {
  action: string
  reason: string
}

export interface ConnectionErrorEvent {
  error: string
  details?: string
}

/**
 * Type-safe Socket.io instance
 */
export interface TypedSocket {
  on<K extends keyof ServerToClientEvents>(
    event: K,
    listener: ServerToClientEvents[K]
  ): void

  emit<K extends keyof ClientToServerEvents>(
    event: K,
    ...args: Parameters<ClientToServerEvents[K]>
  ): void

  off<K extends keyof ServerToClientEvents>(
    event: K,
    listener?: ServerToClientEvents[K]
  ): void

  connect(): void
  disconnect(): void

  readonly connected: boolean
  readonly id: string
}
