import { describe, it, expect, beforeEach, vi } from 'vitest'
import { mount } from '@vue/test-utils'
import GameplayPanel from '~/components/Gameplay/GameplayPanel.vue'
import type { RollData, PlayResult } from '~/types'
import DiceRoller from '~/components/Gameplay/DiceRoller.vue'
import OutcomeWizard from '~/components/Gameplay/OutcomeWizard.vue'
import PlayResultComponent from '~/components/Gameplay/PlayResult.vue'

describe('GameplayPanel', () => {
  const createRollData = (): RollData => ({
    roll_id: 'test-roll-123',
    d6_one: 3,
    d6_two_a: 2,
    d6_two_b: 4,
    d6_two_total: 6,
    chaos_d20: 15,
    resolution_d20: 8,
    check_wild_pitch: false,
    check_passed_ball: false,
    timestamp: '2025-01-13T12:00:00Z',
  })

  const createPlayResult = (): PlayResult => ({
    play_number: 1,
    outcome: 'STRIKEOUT',
    description: 'Mike Trout strikes out swinging',
    outs_recorded: 1,
    runs_scored: 0,
    runners_advanced: [],
    batter_result: null,
    new_state: {},
    is_hit: false,
    is_out: true,
    is_walk: false,
    is_strikeout: true,
  })

  const defaultProps = {
    gameId: 'game-123',
    isMyTurn: false,
    canRollDice: false,
    pendingRoll: null,
    lastPlayResult: null,
    canSubmitOutcome: false,
  }

  beforeEach(() => {
    vi.clearAllTimers()
  })

  // ============================================================================
  // Rendering Tests
  // ============================================================================

  describe('Rendering', () => {
    it('renders gameplay panel container', () => {
      const wrapper = mount(GameplayPanel, {
        props: defaultProps,
      })

      expect(wrapper.find('.gameplay-panel').exists()).toBe(true)
      expect(wrapper.text()).toContain('Gameplay')
    })

    it('renders panel header with status', () => {
      const wrapper = mount(GameplayPanel, {
        props: defaultProps,
      })

      expect(wrapper.find('.panel-header').exists()).toBe(true)
      expect(wrapper.find('.status-indicator').exists()).toBe(true)
      expect(wrapper.find('.status-text').exists()).toBe(true)
    })
  })

  // ============================================================================
  // Workflow State: Idle Tests
  // ============================================================================

  describe('Workflow State: Idle', () => {
    it('shows idle state when canRollDice is false', () => {
      const wrapper = mount(GameplayPanel, {
        props: {
          ...defaultProps,
          canRollDice: false,
        },
      })

      expect(wrapper.find('.state-idle').exists()).toBe(true)
      expect(wrapper.text()).toContain('Waiting for strategic decisions')
    })

    it('displays idle status indicator', () => {
      const wrapper = mount(GameplayPanel, {
        props: defaultProps,
      })

      expect(wrapper.find('.status-idle').exists()).toBe(true)
      expect(wrapper.find('.status-text').text()).toBe('Waiting')
    })
  })

  // ============================================================================
  // Workflow State: Ready to Roll Tests
  // ============================================================================

  describe('Workflow State: Ready to Roll', () => {
    it('shows ready state when canRollDice is true and my turn', () => {
      const wrapper = mount(GameplayPanel, {
        props: {
          ...defaultProps,
          canRollDice: true,
          isMyTurn: true,
        },
      })

      expect(wrapper.find('.state-ready').exists()).toBe(true)
      expect(wrapper.text()).toContain('Your turn! Roll the dice')
    })

    it('shows waiting message when not my turn', () => {
      const wrapper = mount(GameplayPanel, {
        props: {
          ...defaultProps,
          canRollDice: true,
          isMyTurn: false,
        },
      })

      expect(wrapper.text()).toContain('Waiting for opponent to roll dice')
    })

    it('renders DiceRoller component when my turn', () => {
      const wrapper = mount(GameplayPanel, {
        props: {
          ...defaultProps,
          canRollDice: true,
          isMyTurn: true,
        },
      })

      expect(wrapper.findComponent(DiceRoller).exists()).toBe(true)
    })

    it('displays active status when ready and my turn', () => {
      const wrapper = mount(GameplayPanel, {
        props: {
          ...defaultProps,
          canRollDice: true,
          isMyTurn: true,
        },
      })

      expect(wrapper.find('.status-active').exists()).toBe(true)
      expect(wrapper.find('.status-text').text()).toBe('Your Turn')
    })

    it('displays opponent turn status when ready but not my turn', () => {
      const wrapper = mount(GameplayPanel, {
        props: {
          ...defaultProps,
          canRollDice: true,
          isMyTurn: false,
        },
      })

      expect(wrapper.find('.status-text').text()).toBe('Opponent Turn')
    })
  })

  // ============================================================================
  // Workflow State: Rolled Tests
  // ============================================================================

  describe('Workflow State: Rolled', () => {
    it('shows rolled state when pendingRoll exists', () => {
      const wrapper = mount(GameplayPanel, {
        props: {
          ...defaultProps,
          pendingRoll: createRollData(),
          canSubmitOutcome: true,
        },
      })

      expect(wrapper.find('.state-rolled').exists()).toBe(true)
    })

    it('renders DiceRoller with roll results', () => {
      const rollData = createRollData()
      const wrapper = mount(GameplayPanel, {
        props: {
          ...defaultProps,
          pendingRoll: rollData,
          canSubmitOutcome: true,
        },
      })

      const diceRoller = wrapper.findComponent(DiceRoller)
      expect(diceRoller.exists()).toBe(true)
      expect(diceRoller.props('pendingRoll')).toEqual(rollData)
      expect(diceRoller.props('canRoll')).toBe(false)
    })

    it('renders OutcomeWizard component', () => {
      const wrapper = mount(GameplayPanel, {
        props: {
          ...defaultProps,
          pendingRoll: createRollData(),
          canSubmitOutcome: true,
        },
      })

      expect(wrapper.findComponent(OutcomeWizard).exists()).toBe(true)
    })

    it('displays active status when outcome entry active', () => {
      const wrapper = mount(GameplayPanel, {
        props: {
          ...defaultProps,
          pendingRoll: createRollData(),
          canSubmitOutcome: true,
        },
      })

      expect(wrapper.find('.status-active').exists()).toBe(true)
      expect(wrapper.find('.status-text').text()).toBe('Enter Outcome')
    })
  })

  // ============================================================================
  // Workflow State: Result Tests
  // ============================================================================

  describe('Workflow State: Result', () => {
    it('shows result state when lastPlayResult exists', () => {
      const wrapper = mount(GameplayPanel, {
        props: {
          ...defaultProps,
          lastPlayResult: createPlayResult(),
        },
      })

      expect(wrapper.find('.state-result').exists()).toBe(true)
    })

    it('renders PlayResult component', () => {
      const playResult = createPlayResult()
      const wrapper = mount(GameplayPanel, {
        props: {
          ...defaultProps,
          lastPlayResult: playResult,
        },
      })

      const playResultComponent = wrapper.findComponent(PlayResultComponent)
      expect(playResultComponent.exists()).toBe(true)
      expect(playResultComponent.props('result')).toEqual(playResult)
    })

    it('displays success status when result shown', () => {
      const wrapper = mount(GameplayPanel, {
        props: {
          ...defaultProps,
          lastPlayResult: createPlayResult(),
        },
      })

      expect(wrapper.find('.status-success').exists()).toBe(true)
      expect(wrapper.find('.status-text').text()).toBe('Play Complete')
    })

    it('prioritizes result state over other states', () => {
      const wrapper = mount(GameplayPanel, {
        props: {
          ...defaultProps,
          canRollDice: true,
          pendingRoll: createRollData(),
          lastPlayResult: createPlayResult(),
        },
      })

      expect(wrapper.find('.state-result').exists()).toBe(true)
      expect(wrapper.find('.state-rolled').exists()).toBe(false)
      expect(wrapper.find('.state-ready').exists()).toBe(false)
    })
  })

  // ============================================================================
  // Event Emission Tests
  // ============================================================================

  describe('Event Emission', () => {
    it('emits rollDice when DiceRoller emits roll', async () => {
      const wrapper = mount(GameplayPanel, {
        props: {
          ...defaultProps,
          canRollDice: true,
          isMyTurn: true,
        },
      })

      const diceRoller = wrapper.findComponent(DiceRoller)
      await diceRoller.vm.$emit('roll')

      expect(wrapper.emitted('rollDice')).toBeTruthy()
      expect(wrapper.emitted('rollDice')).toHaveLength(1)
    })

    it('emits submitOutcome when ManualOutcomeEntry submits', async () => {
      const wrapper = mount(GameplayPanel, {
        props: {
          ...defaultProps,
          pendingRoll: createRollData(),
          canSubmitOutcome: true,
        },
      })

      const outcomeWizard = wrapper.findComponent(OutcomeWizard)
      const payload = { outcome: 'STRIKEOUT' as const, hitLocation: undefined }
      await outcomeWizard.vm.$emit('submit', payload)

      expect(wrapper.emitted('submitOutcome')).toBeTruthy()
      expect(wrapper.emitted('submitOutcome')?.[0]).toEqual([payload])
    })

    it('emits dismissResult when PlayResult emits dismiss', async () => {
      const wrapper = mount(GameplayPanel, {
        props: {
          ...defaultProps,
          lastPlayResult: createPlayResult(),
        },
      })

      const playResult = wrapper.findComponent(PlayResultComponent)
      await playResult.vm.$emit('dismiss')

      expect(wrapper.emitted('dismissResult')).toBeTruthy()
      expect(wrapper.emitted('dismissResult')).toHaveLength(1)
    })
  })

  // ============================================================================
  // Workflow State Transitions Tests
  // ============================================================================

  describe('Workflow State Transitions', () => {
    it('transitions from idle to ready when canRollDice becomes true', async () => {
      const wrapper = mount(GameplayPanel, {
        props: defaultProps,
      })

      expect(wrapper.find('.state-idle').exists()).toBe(true)

      await wrapper.setProps({ canRollDice: true, isMyTurn: true })

      expect(wrapper.find('.state-idle').exists()).toBe(false)
      expect(wrapper.find('.state-ready').exists()).toBe(true)
    })

    it('transitions from ready to rolled when pendingRoll set', async () => {
      const wrapper = mount(GameplayPanel, {
        props: {
          ...defaultProps,
          canRollDice: true,
          isMyTurn: true,
        },
      })

      expect(wrapper.find('.state-ready').exists()).toBe(true)

      await wrapper.setProps({
        pendingRoll: createRollData(),
        canRollDice: false,
        canSubmitOutcome: true,
      })

      expect(wrapper.find('.state-ready').exists()).toBe(false)
      expect(wrapper.find('.state-rolled').exists()).toBe(true)
    })

    it('transitions from rolled to result when lastPlayResult set', async () => {
      const wrapper = mount(GameplayPanel, {
        props: {
          ...defaultProps,
          pendingRoll: createRollData(),
          canSubmitOutcome: true,
        },
      })

      expect(wrapper.find('.state-rolled').exists()).toBe(true)

      await wrapper.setProps({
        lastPlayResult: createPlayResult(),
        pendingRoll: null,
      })

      expect(wrapper.find('.state-rolled').exists()).toBe(false)
      expect(wrapper.find('.state-result').exists()).toBe(true)
    })

    it('transitions from result to idle when result dismissed', async () => {
      const wrapper = mount(GameplayPanel, {
        props: {
          ...defaultProps,
          lastPlayResult: createPlayResult(),
        },
      })

      expect(wrapper.find('.state-result').exists()).toBe(true)

      await wrapper.setProps({ lastPlayResult: null })

      expect(wrapper.find('.state-result').exists()).toBe(false)
      expect(wrapper.find('.state-idle').exists()).toBe(true)
    })
  })

  // ============================================================================
  // Edge Cases
  // ============================================================================

  describe('Edge Cases', () => {
    it('handles multiple rapid state changes', async () => {
      const wrapper = mount(GameplayPanel, {
        props: defaultProps,
      })

      await wrapper.setProps({ canRollDice: true, isMyTurn: true })
      await wrapper.setProps({ pendingRoll: createRollData(), canSubmitOutcome: true })
      await wrapper.setProps({ lastPlayResult: createPlayResult() })

      expect(wrapper.find('.state-result').exists()).toBe(true)
    })

    it('handles missing gameId gracefully', () => {
      const wrapper = mount(GameplayPanel, {
        props: {
          ...defaultProps,
          gameId: '',
        },
      })

      expect(wrapper.find('.gameplay-panel').exists()).toBe(true)
    })

    it('handles all props being null/false', () => {
      const wrapper = mount(GameplayPanel, {
        props: {
          gameId: 'test',
          isMyTurn: false,
          canRollDice: false,
          pendingRoll: null,
          lastPlayResult: null,
          canSubmitOutcome: false,
        },
      })

      expect(wrapper.find('.state-idle').exists()).toBe(true)
    })

    it('clears error when rolling dice', async () => {
      const wrapper = mount(GameplayPanel, {
        props: {
          ...defaultProps,
          canRollDice: true,
          isMyTurn: true,
        },
      })

      // Manually set error (would normally come from failed operation)
      wrapper.vm.error = 'Test error'
      await wrapper.vm.$nextTick()

      const diceRoller = wrapper.findComponent(DiceRoller)
      await diceRoller.vm.$emit('roll')

      expect(wrapper.vm.error).toBeNull()
    })
  })
})
