import { describe, it, expect, vi, beforeEach } from 'vitest'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { ChoiceOption, ChoiceGrid, TextInput, ConfidenceLevel, RecordingControl } from '../../shared/AnswerActions'

// Mock BluePlayButton
vi.mock('@/components/shared/BluePlayButton', () => ({
  BluePlayButton: ({ onPlayStart, disabled, title }: any) => (
    <button
      onClick={onPlayStart}
      disabled={disabled}
      title={title}
      data-testid="blue-play-button"
    >
      播放
    </button>
  )
}))

describe('ChoiceOption', () => {
  const mockOnSelect = vi.fn()

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

  describe('基礎渲染', () => {
    it('應該顯示選項文字', () => {
      render(
        <ChoiceOption
          option="hello"
          index={0}
          onSelect={mockOnSelect}
        />
      )

      expect(screen.getByText('hello')).toBeInTheDocument()
      expect(screen.getByLabelText('選項 1: hello')).toBeInTheDocument()
    })
  })

  describe('選擇狀態樣式', () => {
    it('應該在選中時應用選中樣式', () => {
      render(
        <ChoiceOption
          option="test"
          index={0}
          isSelected={true}
          onSelect={mockOnSelect}
        />
      )

      const button = screen.getByRole('button')
      expect(button).toHaveClass('border-blue-500', 'bg-blue-50', 'text-blue-700')
    })

    it('應該在顯示結果且正確時應用正確樣式', () => {
      render(
        <ChoiceOption
          option="correct"
          index={0}
          isCorrect={true}
          showResult={true}
          onSelect={mockOnSelect}
        />
      )

      const button = screen.getByRole('button')
      expect(button).toHaveClass('border-green-500', 'bg-green-50', 'text-green-700')
    })

    it('應該在顯示結果且錯誤時應用錯誤樣式', () => {
      render(
        <ChoiceOption
          option="wrong"
          index={0}
          isSelected={true}
          isIncorrect={true}
          showResult={true}
          onSelect={mockOnSelect}
        />
      )

      const button = screen.getByRole('button')
      expect(button).toHaveClass('border-red-500', 'bg-red-50', 'text-red-700')
    })
  })

  describe('交互功能', () => {
    it('應該在點擊時調用 onSelect', async () => {
      const user = userEvent.setup()

      render(
        <ChoiceOption
          option="clickable"
          index={0}
          onSelect={mockOnSelect}
        />
      )

      await user.click(screen.getByRole('button'))
      expect(mockOnSelect).toHaveBeenCalledWith('clickable')
    })

    it('應該在 disabled 時不調用 onSelect', async () => {
      const user = userEvent.setup()

      render(
        <ChoiceOption
          option="disabled"
          index={0}
          disabled={true}
          onSelect={mockOnSelect}
        />
      )

      await user.click(screen.getByRole('button'))
      expect(mockOnSelect).not.toHaveBeenCalled()
    })

    it('應該在 showResult 時不調用 onSelect', async () => {
      const user = userEvent.setup()

      render(
        <ChoiceOption
          option="result"
          index={0}
          showResult={true}
          onSelect={mockOnSelect}
        />
      )

      await user.click(screen.getByRole('button'))
      expect(mockOnSelect).not.toHaveBeenCalled()
    })
  })
})

describe('ChoiceGrid', () => {
  const mockOptions = ['option1', 'option2', 'option3', 'option4']
  const mockOnSelect = vi.fn()

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

  describe('基礎渲染', () => {
    it('應該渲染所有選項', () => {
      render(
        <ChoiceGrid
          options={mockOptions}
          onSelect={mockOnSelect}
        />
      )

      mockOptions.forEach(option => {
        expect(screen.getByText(option)).toBeInTheDocument()
      })
    })

    it('應該使用響應式網格布局', () => {
      const { container } = render(
        <ChoiceGrid
          options={mockOptions}
          onSelect={mockOnSelect}
        />
      )

      expect(container.firstChild).toHaveClass('grid', 'grid-cols-1', 'sm:grid-cols-2')
    })
  })

  describe('選擇狀態管理', () => {
    it('應該正確顯示選中狀態', () => {
      render(
        <ChoiceGrid
          options={mockOptions}
          selectedOption="option2"
          onSelect={mockOnSelect}
        />
      )

      const selectedButton = screen.getByLabelText('選項 2: option2')
      expect(selectedButton).toHaveClass('border-blue-500')
    })

    it('應該在顯示結果時正確標記正確答案', () => {
      render(
        <ChoiceGrid
          options={mockOptions}
          selectedOption="option1"
          correctAnswer="option3"
          showResult={true}
          onSelect={mockOnSelect}
        />
      )

      const correctButton = screen.getByLabelText('選項 3: option3')
      const wrongButton = screen.getByLabelText('選項 1: option1')

      expect(correctButton).toHaveClass('border-green-500')
      expect(wrongButton).toHaveClass('border-red-500')
    })
  })
})

describe('TextInput', () => {
  const mockOnChange = vi.fn()
  const mockOnSubmit = vi.fn()

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

  describe('基礎功能', () => {
    it('應該處理文字輸入', async () => {
      const user = userEvent.setup()

      render(
        <TextInput
          value=""
          onChange={mockOnChange}
          onSubmit={mockOnSubmit}
        />
      )

      const input = screen.getByRole('textbox')
      await user.type(input, 'hello')

      expect(mockOnChange).toHaveBeenCalledTimes(5) // 每個字符一次
    })

    it('應該在按Enter時提交', async () => {
      const user = userEvent.setup()

      render(
        <TextInput
          value="test answer"
          onChange={mockOnChange}
          onSubmit={mockOnSubmit}
        />
      )

      const input = screen.getByRole('textbox')
      await user.type(input, '{enter}')

      expect(mockOnSubmit).toHaveBeenCalledWith('test answer')
    })

    it('應該在點擊提交按鈕時提交', async () => {
      const user = userEvent.setup()

      render(
        <TextInput
          value="test answer"
          onChange={mockOnChange}
          onSubmit={mockOnSubmit}
        />
      )

      const submitButton = screen.getByText('提交')
      await user.click(submitButton)

      expect(mockOnSubmit).toHaveBeenCalledWith('test answer')
    })
  })

  describe('提交按鈕狀態', () => {
    it('應該在輸入為空時禁用提交按鈕', () => {
      render(
        <TextInput
          value=""
          onChange={mockOnChange}
          onSubmit={mockOnSubmit}
        />
      )

      const submitButton = screen.getByText('提交')
      expect(submitButton).toBeDisabled()
    })

    it('應該在有輸入時啟用提交按鈕', () => {
      render(
        <TextInput
          value="some text"
          onChange={mockOnChange}
          onSubmit={mockOnSubmit}
        />
      )

      const submitButton = screen.getByText('提交')
      expect(submitButton).not.toBeDisabled()
    })

    it('應該在顯示結果時隱藏提交按鈕', () => {
      render(
        <TextInput
          value="answer"
          showResult={true}
          onChange={mockOnChange}
          onSubmit={mockOnSubmit}
        />
      )

      expect(screen.queryByText('提交')).not.toBeInTheDocument()
    })
  })

  describe('結果顯示', () => {
    it('應該在答錯時顯示正確答案', () => {
      render(
        <TextInput
          value="wrong"
          showResult={true}
          isCorrect={false}
          correctAnswer="correct"
          onChange={mockOnChange}
          onSubmit={mockOnSubmit}
        />
      )

      expect(screen.getByText('正確答案：')).toBeInTheDocument()
      expect(screen.getByText('correct')).toBeInTheDocument()
    })

    it('應該在答對時不顯示正確答案', () => {
      render(
        <TextInput
          value="correct"
          showResult={true}
          isCorrect={true}
          correctAnswer="correct"
          onChange={mockOnChange}
          onSubmit={mockOnSubmit}
        />
      )

      expect(screen.queryByText('正確答案：')).not.toBeInTheDocument()
    })
  })

  describe('輸入樣式', () => {
    it('應該在正確時應用綠色樣式', () => {
      render(
        <TextInput
          value="correct"
          showResult={true}
          isCorrect={true}
          onChange={mockOnChange}
          onSubmit={mockOnSubmit}
        />
      )

      const input = screen.getByRole('textbox')
      expect(input).toHaveClass('border-green-500', 'bg-green-50')
    })

    it('應該在錯誤時應用紅色樣式', () => {
      render(
        <TextInput
          value="wrong"
          showResult={true}
          isCorrect={false}
          onChange={mockOnChange}
          onSubmit={mockOnSubmit}
        />
      )

      const input = screen.getByRole('textbox')
      expect(input).toHaveClass('border-red-500', 'bg-red-50')
    })
  })
})

describe('ConfidenceLevel', () => {
  const mockOnSelect = vi.fn()

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

  describe('基礎渲染', () => {
    it('應該渲染所有信心等級按鈕', () => {
      render(
        <ConfidenceLevel
          onSelect={mockOnSelect}
        />
      )

      expect(screen.getByText('完全不熟')).toBeInTheDocument()
      expect(screen.getByText('完全掌握')).toBeInTheDocument()

      // 檢查所有等級數字
      for (let i = 1; i <= 5; i++) {
        expect(screen.getByText(i.toString())).toBeInTheDocument()
      }
    })
  })

  describe('信心等級選擇', () => {
    it('應該在點擊時調用 onSelect', async () => {
      const user = userEvent.setup()

      render(
        <ConfidenceLevel
          onSelect={mockOnSelect}
        />
      )

      const level3Button = screen.getByText('還算熟悉').closest('button')
      await user.click(level3Button!)

      expect(mockOnSelect).toHaveBeenCalledWith(3)
    })

    it('應該正確顯示選中狀態', () => {
      render(
        <ConfidenceLevel
          selectedLevel={4}
          onSelect={mockOnSelect}
        />
      )

      const selectedButton = screen.getByText('很熟悉').closest('button')
      expect(selectedButton).toHaveClass('ring-4', 'ring-opacity-50')
    })
  })
})

describe('RecordingControl', () => {
  const mockOnStartRecording = vi.fn()
  const mockOnStopRecording = vi.fn()
  const mockOnPlayback = vi.fn()
  const mockOnSubmit = vi.fn()

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

  describe('錄音狀態管理', () => {
    it('應該在非錄音狀態顯示開始按鈕', () => {
      render(
        <RecordingControl
          isRecording={false}
          hasRecording={false}
          onStartRecording={mockOnStartRecording}
          onStopRecording={mockOnStopRecording}
          onPlayback={mockOnPlayback}
          onSubmit={mockOnSubmit}
        />
      )

      expect(screen.getByText('🎤')).toBeInTheDocument()
      expect(screen.getByText('點擊開始錄音')).toBeInTheDocument()
    })

    it('應該在錄音狀態顯示停止按鈕', () => {
      render(
        <RecordingControl
          isRecording={true}
          hasRecording={false}
          onStartRecording={mockOnStartRecording}
          onStopRecording={mockOnStopRecording}
          onPlayback={mockOnPlayback}
          onSubmit={mockOnSubmit}
        />
      )

      expect(screen.getByText('⏹️')).toBeInTheDocument()
      expect(screen.getByText('錄音中... 點擊停止')).toBeInTheDocument()
    })

    it('應該在有錄音時顯示播放和提交按鈕', () => {
      render(
        <RecordingControl
          isRecording={false}
          hasRecording={true}
          onStartRecording={mockOnStartRecording}
          onStopRecording={mockOnStopRecording}
          onPlayback={mockOnPlayback}
          onSubmit={mockOnSubmit}
        />
      )

      expect(screen.getByText('錄音完成')).toBeInTheDocument()
      expect(screen.getByTestId('blue-play-button')).toBeInTheDocument()
      expect(screen.getByText('提交錄音')).toBeInTheDocument()
    })
  })

  describe('錄音操作', () => {
    it('應該在點擊時開始錄音', async () => {
      const user = userEvent.setup()

      render(
        <RecordingControl
          isRecording={false}
          hasRecording={false}
          onStartRecording={mockOnStartRecording}
          onStopRecording={mockOnStopRecording}
          onPlayback={mockOnPlayback}
          onSubmit={mockOnSubmit}
        />
      )

      const recordButton = screen.getByRole('button')
      await user.click(recordButton)

      expect(mockOnStartRecording).toHaveBeenCalledTimes(1)
    })

    it('應該在錄音時點擊停止錄音', async () => {
      const user = userEvent.setup()

      render(
        <RecordingControl
          isRecording={true}
          hasRecording={false}
          onStartRecording={mockOnStartRecording}
          onStopRecording={mockOnStopRecording}
          onPlayback={mockOnPlayback}
          onSubmit={mockOnSubmit}
        />
      )

      const recordButton = screen.getByRole('button')
      await user.click(recordButton)

      expect(mockOnStopRecording).toHaveBeenCalledTimes(1)
    })

    it('應該在有錄音時能播放', async () => {
      const user = userEvent.setup()

      render(
        <RecordingControl
          isRecording={false}
          hasRecording={true}
          onStartRecording={mockOnStartRecording}
          onStopRecording={mockOnStopRecording}
          onPlayback={mockOnPlayback}
          onSubmit={mockOnSubmit}
        />
      )

      const playButton = screen.getByTestId('blue-play-button')
      await user.click(playButton)

      expect(mockOnPlayback).toHaveBeenCalledTimes(1)
    })

    it('應該在有錄音時能提交', async () => {
      const user = userEvent.setup()

      render(
        <RecordingControl
          isRecording={false}
          hasRecording={true}
          onStartRecording={mockOnStartRecording}
          onStopRecording={mockOnStopRecording}
          onPlayback={mockOnPlayback}
          onSubmit={mockOnSubmit}
        />
      )

      const submitButton = screen.getByText('提交錄音')
      await user.click(submitButton)

      expect(mockOnSubmit).toHaveBeenCalledTimes(1)
    })
  })

  describe('禁用狀態', () => {
    it('應該在 disabled 時禁用所有按鈕', () => {
      render(
        <RecordingControl
          isRecording={false}
          hasRecording={true}
          disabled={true}
          onStartRecording={mockOnStartRecording}
          onStopRecording={mockOnStopRecording}
          onPlayback={mockOnPlayback}
          onSubmit={mockOnSubmit}
        />
      )

      // 錄音按鈕應該禁用
      const recordButton = screen.getByText('🎤')
      expect(recordButton).toBeDisabled()

      // 播放和提交按鈕應該禁用
      const playButton = screen.getByTestId('blue-play-button')
      const submitButton = screen.getByText('提交錄音')
      expect(playButton).toBeDisabled()
      expect(submitButton).toBeDisabled()
    })
  })
})