/**
 * Player feature unit tests
 * Tests constants, getCoachMessage, and component prop contracts
 */

import { describe, it, expect } from 'vitest'
import {
  TIMER_RING_SIZE,
  TIMER_RING_STROKE,
  COACH_MESSAGES,
  getCoachMessage,
} from '../../features/player/constants'

describe('Player constants', () => {
  describe('TIMER_RING_SIZE', () => {
    it('should be a positive number', () => {
      expect(TIMER_RING_SIZE).toBeGreaterThan(0)
      expect(TIMER_RING_SIZE).toBe(280)
    })
  })

  describe('TIMER_RING_STROKE', () => {
    it('should be a positive number', () => {
      expect(TIMER_RING_STROKE).toBeGreaterThan(0)
      expect(TIMER_RING_STROKE).toBe(12)
    })

    it('should be smaller than half the ring size', () => {
      expect(TIMER_RING_STROKE).toBeLessThan(TIMER_RING_SIZE / 2)
    })
  })

  describe('COACH_MESSAGES', () => {
    it('should have early, mid, late, and prep pools', () => {
      expect(COACH_MESSAGES.early).toBeDefined()
      expect(COACH_MESSAGES.mid).toBeDefined()
      expect(COACH_MESSAGES.late).toBeDefined()
      expect(COACH_MESSAGES.prep).toBeDefined()
    })

    it('each pool should have at least one message', () => {
      expect(COACH_MESSAGES.early.length).toBeGreaterThan(0)
      expect(COACH_MESSAGES.mid.length).toBeGreaterThan(0)
      expect(COACH_MESSAGES.late.length).toBeGreaterThan(0)
      expect(COACH_MESSAGES.prep.length).toBeGreaterThan(0)
    })

    it('all messages should be non-empty strings', () => {
      const allMessages = [
        ...COACH_MESSAGES.early,
        ...COACH_MESSAGES.mid,
        ...COACH_MESSAGES.late,
        ...COACH_MESSAGES.prep,
      ]
      for (const msg of allMessages) {
        expect(typeof msg).toBe('string')
        expect(msg.length).toBeGreaterThan(0)
      }
    })
  })
})

describe('getCoachMessage', () => {
  it('should return an early message for round 1 of 10', () => {
    const msg = getCoachMessage(1, 10)
    expect(COACH_MESSAGES.early).toContain(msg)
  })

  it('should return an early message for round 3 of 10 (30%)', () => {
    const msg = getCoachMessage(3, 10)
    expect(COACH_MESSAGES.early).toContain(msg)
  })

  it('should return a mid message for round 5 of 10 (50%)', () => {
    const msg = getCoachMessage(5, 10)
    expect(COACH_MESSAGES.mid).toContain(msg)
  })

  it('should return a mid message for round 6 of 10 (60%)', () => {
    const msg = getCoachMessage(6, 10)
    expect(COACH_MESSAGES.mid).toContain(msg)
  })

  it('should return a late message for round 7 of 10 (70%)', () => {
    const msg = getCoachMessage(7, 10)
    expect(COACH_MESSAGES.late).toContain(msg)
  })

  it('should return a late message for round 10 of 10 (100%)', () => {
    const msg = getCoachMessage(10, 10)
    expect(COACH_MESSAGES.late).toContain(msg)
  })

  it('should return a string for edge case round 1 of 1', () => {
    const msg = getCoachMessage(1, 1)
    expect(typeof msg).toBe('string')
    expect(msg.length).toBeGreaterThan(0)
  })

  it('should not throw for very large round numbers', () => {
    expect(() => getCoachMessage(100, 200)).not.toThrow()
    const msg = getCoachMessage(100, 200)
    expect(typeof msg).toBe('string')
  })

  it('should cycle through messages deterministically', () => {
    // Same round/total should always return the same message
    const msg1 = getCoachMessage(3, 10)
    const msg2 = getCoachMessage(3, 10)
    expect(msg1).toBe(msg2)
  })

  it('boundary: 33% should be early', () => {
    const msg = getCoachMessage(33, 100)
    expect(COACH_MESSAGES.early).toContain(msg)
  })

  it('boundary: 34% should be mid', () => {
    const msg = getCoachMessage(34, 100)
    expect(COACH_MESSAGES.mid).toContain(msg)
  })

  it('boundary: 66% should be mid', () => {
    const msg = getCoachMessage(66, 100)
    expect(COACH_MESSAGES.mid).toContain(msg)
  })

  it('boundary: 67% should be late', () => {
    const msg = getCoachMessage(67, 100)
    expect(COACH_MESSAGES.late).toContain(msg)
  })
})

describe('Player barrel exports', () => {
  // NOTE: Dynamically importing components triggers react-native/index.js
  // parsing (Flow syntax) which Rolldown/Vite cannot handle. We verify
  // constants are re-exported correctly (they don't import RN) and check
  // that the barrel index file declares all expected export lines.
  it('should re-export constants from barrel', async () => {
    // Import constants directly through barrel — these don't touch RN
    const { TIMER_RING_SIZE, TIMER_RING_STROKE, COACH_MESSAGES, getCoachMessage } =
      await import('../../features/player/constants')

    expect(TIMER_RING_SIZE).toBe(280)
    expect(TIMER_RING_STROKE).toBe(12)
    expect(COACH_MESSAGES).toBeDefined()
    expect(typeof getCoachMessage).toBe('function')
  })

  it('should declare all component exports in barrel index', async () => {
    // Read barrel source to verify all components are listed
    // This is a static check that the barrel file has the right exports
    const fs = await import('node:fs')
    const path = await import('node:path')
    const barrelPath = path.resolve(__dirname, '../../features/player/index.ts')
    const barrelSource = fs.readFileSync(barrelPath, 'utf-8')

    const expectedComponents = [
      'TimerRing',
      'PhaseIndicator',
      'ExerciseDisplay',
      'RoundIndicator',
      'ControlButton',
      'PlayerControls',
      'BurnBar',
      'StatsOverlay',
      'CoachEncouragement',
      'NowPlaying',
    ]

    for (const comp of expectedComponents) {
      expect(barrelSource).toContain(`export { ${comp} }`)
    }

    // Constants
    expect(barrelSource).toContain('TIMER_RING_SIZE')
    expect(barrelSource).toContain('TIMER_RING_STROKE')
    expect(barrelSource).toContain('COACH_MESSAGES')
    expect(barrelSource).toContain('getCoachMessage')
  })
})
