/**
 * Game Store Tests
 *
 * Tests for game state management, play history, and computed properties.
 */

import { describe, it, expect, beforeEach } from 'vitest'
import { setActivePinia, createPinia } from 'pinia'
import { useGameStore } from '~/store/game'
import type { GameState, PlayResult, DecisionPrompt, RollData, Lineup } from '~/types'

// Mock game state factory
const createMockGameState = (overrides?: Partial<GameState>): GameState => ({
  game_id: 'game-123',
  league_id: 'sba',
  status: 'active',
  inning: 1,
  half: 'top',
  outs: 0,
  balls: 0,
  strikes: 0,
  home_score: 0,
  away_score: 0,
  home_team_id: 1,
  away_team_id: 2,
  home_team_is_ai: false,
  away_team_is_ai: false,
  on_first: null,
  on_second: null,
  on_third: null,
  current_batter: null,
  current_pitcher: null,
  current_catcher: null,
  decision_phase: 'awaiting_defensive',
  ...overrides,
})

describe('useGameStore', () => {
  beforeEach(() => {
    // Ensure process.env exists before creating Pinia
    if (!process.env) {
      (process as any).env = {}
    }
    process.env.NODE_ENV = 'test'

    setActivePinia(createPinia())
  })

  describe('initialization', () => {
    it('initializes with null/empty state', () => {
      const store = useGameStore()

      expect(store.gameState).toBeNull()
      expect(store.homeLineup).toEqual([])
      expect(store.awayLineup).toEqual([])
      expect(store.playHistory).toEqual([])
      expect(store.currentDecisionPrompt).toBeNull()
      expect(store.pendingRoll).toBeNull()
      expect(store.isConnected).toBe(false)
      expect(store.isLoading).toBe(false)
      expect(store.error).toBeNull()
    })

    it('has null computed properties on init', () => {
      const store = useGameStore()

      expect(store.gameId).toBeNull()
      expect(store.leagueId).toBeNull()
      expect(store.currentBatter).toBeNull()
      expect(store.currentPitcher).toBeNull()
    })

    it('has default computed values on init', () => {
      const store = useGameStore()

      expect(store.currentInning).toBe(1)
      expect(store.currentHalf).toBe('top')
      expect(store.outs).toBe(0)
      expect(store.homeScore).toBe(0)
      expect(store.awayScore).toBe(0)
      expect(store.gameStatus).toBe('pending')
    })
  })

  describe('setting game state', () => {
    it('sets complete game state', () => {
      const store = useGameStore()
      const mockState = createMockGameState()

      store.setGameState(mockState)

      expect(store.gameState).toEqual(mockState)
      expect(store.gameId).toBe('game-123')
      expect(store.leagueId).toBe('sba')
      expect(store.error).toBeNull()
    })

    it('updates partial game state', () => {
      const store = useGameStore()
      const mockState = createMockGameState()

      store.setGameState(mockState)
      store.updateGameState({ outs: 2, strikes: 2 })

      expect(store.outs).toBe(2)
      expect(store.strikes).toBe(2)
      expect(store.gameId).toBe('game-123') // Other fields unchanged
    })

    it('does not update if no game state exists', () => {
      const store = useGameStore()

      // Should not crash
      expect(() => store.updateGameState({ outs: 1 })).not.toThrow()
      expect(store.gameState).toBeNull()
    })
  })

  describe('computed properties', () => {
    it('computes game status flags', () => {
      const store = useGameStore()

      store.setGameState(createMockGameState({ status: 'pending' }))
      expect(store.isGameActive).toBe(false)
      expect(store.isGameComplete).toBe(false)

      store.setGameState(createMockGameState({ status: 'active' }))
      expect(store.isGameActive).toBe(true)
      expect(store.isGameComplete).toBe(false)

      store.setGameState(createMockGameState({ status: 'completed' }))
      expect(store.isGameActive).toBe(false)
      expect(store.isGameComplete).toBe(true)
    })

    it('computes runners on base correctly', () => {
      const store = useGameStore()

      // No runners
      store.setGameState(createMockGameState())
      expect(store.runnersOnBase).toEqual([])
      expect(store.basesLoaded).toBe(false)
      expect(store.runnerInScoringPosition).toBe(false)

      // Runner on first
      store.setGameState(createMockGameState({ on_first: 123 }))
      expect(store.runnersOnBase).toEqual([1])
      expect(store.basesLoaded).toBe(false)
      expect(store.runnerInScoringPosition).toBe(false)

      // Runner in scoring position (second)
      store.setGameState(createMockGameState({ on_second: 456 }))
      expect(store.runnersOnBase).toEqual([2])
      expect(store.runnerInScoringPosition).toBe(true)

      // Bases loaded
      store.setGameState(createMockGameState({
        on_first: 123,
        on_second: 456,
        on_third: 789,
      }))
      expect(store.runnersOnBase).toEqual([1, 2, 3])
      expect(store.basesLoaded).toBe(true)
      expect(store.runnerInScoringPosition).toBe(true)
    })

    it('computes batting and fielding team IDs', () => {
      const store = useGameStore()

      // Top of inning: away bats, home fields
      store.setGameState(createMockGameState({ half: 'top' }))
      expect(store.battingTeamId).toBe(2) // away
      expect(store.fieldingTeamId).toBe(1) // home

      // Bottom of inning: home bats, away fields
      store.setGameState(createMockGameState({ half: 'bottom' }))
      expect(store.battingTeamId).toBe(1) // home
      expect(store.fieldingTeamId).toBe(2) // away
    })

    it('computes AI team flags', () => {
      const store = useGameStore()

      // Top of inning with away team AI
      store.setGameState(createMockGameState({
        half: 'top',
        away_team_is_ai: true,
        home_team_is_ai: false,
      }))
      expect(store.isBattingTeamAI).toBe(true)
      expect(store.isFieldingTeamAI).toBe(false)

      // Bottom of inning with home team AI
      store.setGameState(createMockGameState({
        half: 'bottom',
        home_team_is_ai: true,
        away_team_is_ai: false,
      }))
      expect(store.isBattingTeamAI).toBe(true)
      expect(store.isFieldingTeamAI).toBe(false)
    })
  })

  describe('play history management', () => {
    it('adds play to history', () => {
      const store = useGameStore()
      const play: PlayResult = {
        play_number: 1,
        outcome: 'SINGLE_1',
        description: 'Single to center field',
        runs_scored: 0,
        outs_recorded: 0,
        new_state: {},
      }

      store.addPlayToHistory(play)

      expect(store.playHistory.length).toBe(1)
      expect(store.playHistory[0]).toEqual(play)
    })

    it('updates game state from play result', () => {
      const store = useGameStore()
      store.setGameState(createMockGameState())

      const play: PlayResult = {
        play_number: 1,
        outcome: 'STRIKEOUT',
        description: 'Struck out swinging',
        runs_scored: 0,
        outs_recorded: 1,
        new_state: { outs: 1 },
      }

      store.addPlayToHistory(play)

      expect(store.outs).toBe(1)
    })

    it('returns recent plays in reverse order', () => {
      const store = useGameStore()

      // Add 15 plays
      for (let i = 1; i <= 15; i++) {
        store.addPlayToHistory({
          play_number: i,
          outcome: 'TEST',
          description: `Play ${i}`,
          runs_scored: 0,
          outs_recorded: 0,
          new_state: {},
        })
      }

      const recent = store.recentPlays

      // Should return last 10 plays in reverse order
      expect(recent.length).toBe(10)
      expect(recent[0].play_number).toBe(15) // Most recent first
      expect(recent[9].play_number).toBe(6) // 10th most recent
    })
  })

  describe('decision prompt management', () => {
    it('sets decision prompt', () => {
      const store = useGameStore()
      const prompt: DecisionPrompt = {
        phase: 'awaiting_defensive',
        role: 'home',
        timeout_seconds: 30,
      }

      store.setDecisionPrompt(prompt)

      expect(store.currentDecisionPrompt).toEqual(prompt)
      expect(store.needsDefensiveDecision).toBe(true)
    })

    it('identifies defensive decision need', () => {
      const store = useGameStore()

      store.setDecisionPrompt({ phase: 'awaiting_defensive', role: 'home', timeout_seconds: 30 })
      expect(store.needsDefensiveDecision).toBe(true)
      expect(store.needsOffensiveDecision).toBe(false)
    })

    it('identifies offensive decision need', () => {
      const store = useGameStore()

      store.setDecisionPrompt({ phase: 'awaiting_offensive', role: 'away', timeout_seconds: 30 })
      expect(store.needsOffensiveDecision).toBe(true)
      expect(store.needsDefensiveDecision).toBe(false)
    })

    it('identifies stolen base decision need', () => {
      const store = useGameStore()

      store.setDecisionPrompt({ phase: 'awaiting_stolen_base', role: 'away', timeout_seconds: 30 })
      expect(store.needsStolenBaseDecision).toBe(true)
    })

    it('clears decision prompt', () => {
      const store = useGameStore()

      store.setDecisionPrompt({ phase: 'defense', role: 'home', timeout_seconds: 30 })
      expect(store.currentDecisionPrompt).not.toBeNull()

      store.clearDecisionPrompt()
      expect(store.currentDecisionPrompt).toBeNull()
    })
  })

  describe('dice roll management', () => {
    it('sets pending roll', () => {
      const store = useGameStore()
      const roll: RollData = {
        roll_id: 'roll-123',
        d6_one: 3,
        d6_two_a: 4,
        d6_two_b: 2,
        chaos_d20: 15,
        resolution_d20: 8,
      }

      store.setPendingRoll(roll)

      expect(store.pendingRoll).toEqual(roll)
    })

    it('computes canRollDice correctly', () => {
      const store = useGameStore()

      // No game state
      expect(store.canRollDice).toBe(false)

      // In resolution phase, no pending roll
      store.setGameState(createMockGameState({ decision_phase: 'resolution' }))
      expect(store.canRollDice).toBe(true)

      // Has pending roll
      store.setPendingRoll({
        roll_id: 'roll-123',
        d6_one: 3,
        d6_two_a: 4,
        d6_two_b: 2,
        chaos_d20: 15,
        resolution_d20: 8,
      })
      expect(store.canRollDice).toBe(false)
    })

    it('computes canSubmitOutcome correctly', () => {
      const store = useGameStore()

      expect(store.canSubmitOutcome).toBe(false)

      store.setPendingRoll({
        roll_id: 'roll-123',
        d6_one: 3,
        d6_two_a: 4,
        d6_two_b: 2,
        chaos_d20: 15,
        resolution_d20: 8,
      })

      expect(store.canSubmitOutcome).toBe(true)
    })

    it('clears pending roll', () => {
      const store = useGameStore()

      store.setPendingRoll({
        roll_id: 'roll-123',
        d6_one: 3,
        d6_two_a: 4,
        d6_two_b: 2,
        chaos_d20: 15,
        resolution_d20: 8,
      })
      expect(store.pendingRoll).not.toBeNull()

      store.clearPendingRoll()
      expect(store.pendingRoll).toBeNull()
    })
  })

  describe('connection and loading state', () => {
    it('sets connection status', () => {
      const store = useGameStore()

      expect(store.isConnected).toBe(false)

      store.setConnected(true)
      expect(store.isConnected).toBe(true)

      store.setConnected(false)
      expect(store.isConnected).toBe(false)
    })

    it('sets loading state', () => {
      const store = useGameStore()

      expect(store.isLoading).toBe(false)

      store.setLoading(true)
      expect(store.isLoading).toBe(true)

      store.setLoading(false)
      expect(store.isLoading).toBe(false)
    })

    it('sets error message', () => {
      const store = useGameStore()

      expect(store.error).toBeNull()

      store.setError('Connection failed')
      expect(store.error).toBe('Connection failed')

      store.setError(null)
      expect(store.error).toBeNull()
    })
  })

  describe('lineup management', () => {
    it('sets both lineups', () => {
      const store = useGameStore()
      const homeLineup: Lineup[] = [
        {
          id: 1,
          game_id: 'game-123',
          team_id: 1,
          card_id: 100,
          position: 'SS',
          batting_order: 1,
          is_starter: true,
          is_active: true,
          player: { id: 100, name: 'Player 1', image: '' },
        },
      ]
      const awayLineup: Lineup[] = [
        {
          id: 2,
          game_id: 'game-123',
          team_id: 2,
          card_id: 200,
          position: 'CF',
          batting_order: 1,
          is_starter: true,
          is_active: true,
          player: { id: 200, name: 'Player 2', image: '' },
        },
      ]

      store.setLineups(homeLineup, awayLineup)

      expect(store.homeLineup).toEqual(homeLineup)
      expect(store.awayLineup).toEqual(awayLineup)
    })

    it('updates lineup for specific team', () => {
      const store = useGameStore()
      store.setGameState(createMockGameState())

      const updatedLineup: Lineup[] = [
        {
          id: 3,
          game_id: 'game-123',
          team_id: 1,
          card_id: 300,
          position: 'P',
          batting_order: null,
          is_starter: false,
          is_active: true,
          player: { id: 300, name: 'Relief Pitcher', image: '' },
        },
      ]

      store.updateLineup(1, updatedLineup) // Update home team

      expect(store.homeLineup).toEqual(updatedLineup)
    })
  })

  describe('reset functionality', () => {
    it('resets all game state', () => {
      const store = useGameStore()

      // Set up some state
      store.setGameState(createMockGameState())
      store.addPlayToHistory({
        play_number: 1,
        outcome: 'SINGLE_1',
        description: 'Single',
        runs_scored: 0,
        outs_recorded: 0,
        new_state: {},
      })
      store.setConnected(true)
      store.setLoading(true)
      store.setError('Error')

      // Reset
      store.resetGame()

      // Verify everything is reset
      expect(store.gameState).toBeNull()
      expect(store.homeLineup).toEqual([])
      expect(store.awayLineup).toEqual([])
      expect(store.playHistory).toEqual([])
      expect(store.currentDecisionPrompt).toBeNull()
      expect(store.pendingRoll).toBeNull()
      expect(store.isConnected).toBe(false)
      expect(store.isLoading).toBe(false)
      expect(store.error).toBeNull()
    })
  })
})
