import { describe, it, expect, vi, beforeEach } from 'vitest'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { renderHook, act } from '@testing-library/react'
import { BaseTestComponent, useTestAnswer } from '../../shared/BaseTestComponent'

// Mock 依賴組件
vi.mock('@/components/review/shared', () => ({
  ErrorReportButton: ({ onClick }: any) => (
    <button onClick={onClick} data-testid="error-report-button">
      回報錯誤
    </button>
  ),
  TestHeader: ({ title, cefr }: any) => (
    <div data-testid="test-header">
      <h2>{title}</h2>
      <span>CEFR: {cefr}</span>
    </div>
  )
}))

describe('BaseTestComponent', () => {
  const mockCardData = {
    id: 'test-1',
    word: 'hello',
    definition: 'a greeting',
    example: 'Hello world',
    translation: '你好',
    pronunciation: '/həˈloʊ/',
    cefr: 'A1',
    synonyms: [],
    exampleImage: undefined
  }

  const mockOnReportError = vi.fn()

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

  describe('基礎渲染', () => {
    it('應該正確渲染測驗標題和基本結構', () => {
      render(
        <BaseTestComponent
          cardData={mockCardData}
          testTitle="測試標題"
          onReportError={mockOnReportError}
        >
          <div data-testid="test-content">測試內容</div>
        </BaseTestComponent>
      )

      expect(screen.getByTestId('test-header')).toBeInTheDocument()
      expect(screen.getByText('測試標題')).toBeInTheDocument()
      expect(screen.getByText('CEFR: A1')).toBeInTheDocument()
      expect(screen.getByTestId('test-content')).toBeInTheDocument()
    })

    it('應該顯示錯誤回報按鈕', () => {
      render(
        <BaseTestComponent
          cardData={mockCardData}
          testTitle="測試"
          onReportError={mockOnReportError}
        >
          <div>內容</div>
        </BaseTestComponent>
      )

      expect(screen.getByTestId('error-report-button')).toBeInTheDocument()
    })

    it('應該在有說明時顯示說明文字', () => {
      render(
        <BaseTestComponent
          cardData={mockCardData}
          testTitle="測試"
          instructions="這是測試說明"
          onReportError={mockOnReportError}
        >
          <div>內容</div>
        </BaseTestComponent>
      )

      expect(screen.getByText('這是測試說明')).toBeInTheDocument()
    })
  })

  describe('結果顯示', () => {
    it('應該在 showResult 為 true 時顯示結果內容', () => {
      render(
        <BaseTestComponent
          cardData={mockCardData}
          testTitle="測試"
          showResult={true}
          resultContent={<div data-testid="result">測試結果</div>}
          onReportError={mockOnReportError}
        >
          <div>內容</div>
        </BaseTestComponent>
      )

      expect(screen.getByTestId('result')).toBeInTheDocument()
    })

    it('應該在 showResult 為 false 時隱藏結果內容', () => {
      render(
        <BaseTestComponent
          cardData={mockCardData}
          testTitle="測試"
          showResult={false}
          resultContent={<div data-testid="result">測試結果</div>}
          onReportError={mockOnReportError}
        >
          <div>內容</div>
        </BaseTestComponent>
      )

      expect(screen.queryByTestId('result')).not.toBeInTheDocument()
    })
  })

  describe('錯誤回報功能', () => {
    it('應該在點擊錯誤回報按鈕時調用 onReportError', async () => {
      const user = userEvent.setup()

      render(
        <BaseTestComponent
          cardData={mockCardData}
          testTitle="測試"
          onReportError={mockOnReportError}
        >
          <div>內容</div>
        </BaseTestComponent>
      )

      const errorButton = screen.getByTestId('error-report-button')
      await user.click(errorButton)

      expect(mockOnReportError).toHaveBeenCalledTimes(1)
    })
  })

  describe('自定義樣式', () => {
    it('應該應用自定義 className', () => {
      const { container } = render(
        <BaseTestComponent
          cardData={mockCardData}
          testTitle="測試"
          className="custom-test-class"
          onReportError={mockOnReportError}
        >
          <div>內容</div>
        </BaseTestComponent>
      )

      expect(container.firstChild).toHaveClass('custom-test-class')
    })
  })
})

describe('useTestAnswer Hook', () => {
  const mockOnAnswer = vi.fn()

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

  describe('初始狀態', () => {
    it('應該有正確的初始值', () => {
      const { result } = renderHook(() => useTestAnswer(mockOnAnswer))

      expect(result.current.selectedAnswer).toBeNull()
      expect(result.current.showResult).toBe(false)
    })
  })

  describe('答題功能', () => {
    it('應該在 handleAnswer 時更新狀態並調用回調', () => {
      const { result } = renderHook(() => useTestAnswer(mockOnAnswer))

      act(() => {
        result.current.handleAnswer('test answer')
      })

      expect(result.current.selectedAnswer).toBe('test answer')
      expect(result.current.showResult).toBe(true)
      expect(mockOnAnswer).toHaveBeenCalledWith('test answer')
    })

    it('應該防止重複提交', async () => {
      const { result } = renderHook(() => useTestAnswer(mockOnAnswer))

      // 第一次提交
      act(() => {
        result.current.handleAnswer('first answer')
      })

      expect(result.current.showResult).toBe(true)
      expect(mockOnAnswer).toHaveBeenCalledTimes(1)

      // 第二次提交應該被阻止
      act(() => {
        result.current.handleAnswer('second answer')
      })

      // onAnswer 不應該被再次調用
      expect(mockOnAnswer).toHaveBeenCalledTimes(1)
      expect(mockOnAnswer).toHaveBeenLastCalledWith('first answer')
    })
  })

  describe('重置功能', () => {
    it('應該正確重置所有狀態', () => {
      const { result } = renderHook(() => useTestAnswer(mockOnAnswer))

      // 先設置一些狀態
      act(() => {
        result.current.handleAnswer('test answer')
      })

      expect(result.current.selectedAnswer).toBe('test answer')
      expect(result.current.showResult).toBe(true)

      // 重置
      act(() => {
        result.current.resetAnswer()
      })

      expect(result.current.selectedAnswer).toBeNull()
      expect(result.current.showResult).toBe(false)
    })
  })

  describe('邊界情況', () => {
    it('應該處理空字符串答案', () => {
      const { result } = renderHook(() => useTestAnswer(mockOnAnswer))

      act(() => {
        result.current.handleAnswer('')
      })

      expect(result.current.selectedAnswer).toBe('')
      expect(mockOnAnswer).toHaveBeenCalledWith('')
    })

    it('應該處理多次重置', () => {
      const { result } = renderHook(() => useTestAnswer(mockOnAnswer))

      act(() => {
        result.current.resetAnswer()
        result.current.resetAnswer()
        result.current.resetAnswer()
      })

      expect(result.current.selectedAnswer).toBeNull()
      expect(result.current.showResult).toBe(false)
    })
  })

  describe('Hook 穩定性', () => {
    it('應該在依賴未變時保持函數引用穩定', () => {
      const { result, rerender } = renderHook(() => useTestAnswer(mockOnAnswer))

      const firstHandleAnswer = result.current.handleAnswer
      const firstResetAnswer = result.current.resetAnswer

      rerender()

      expect(result.current.handleAnswer).toBe(firstHandleAnswer)
      expect(result.current.resetAnswer).toBe(firstResetAnswer)
    })
  })
})